将 Swashbuckle 用于 Asp.net 核心,如何将模型添加到生成的模型列表中?
Using Swashbuckle for Asp.net core how can I add a model to the generated model list?
我正在使用 Swashbuckle 和 ASP.net 内核。它正在制作一个漂亮的网站,底部有一个模型列表。
如何向此列表中添加一个尚未出现的模型?
我在我的一个请求中 return 一个摘要 class,我想列出继承该摘要的所有变体 class。
提前致谢
也许不是最干净的解决方案,但我通过在控制器上方设置 ProducesResponseType
属性实现了同样的效果:
[ProducesResponseType(typeof(object), 200)]
public class FileController : Controller
{
将对象替换为要在模型中显示的对象,并为每个额外的对象创建一个新行。请确保为每个状态码使用不同的状态码,否则它只会显示最后一个。
您可以创建文档过滤器并在全局注册。
public class CustomModelDocumentFilter<T> : IDocumentFilter where T : class
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
context.SchemaRegistry.GetOrRegister(typeof(T));
}
}
然后在您的 Startup
class.
中注册
services.AddSwaggerGen(options =>
{
...
options.DocumentFilter<CustomModelDocumentFilter<MyCustomModel>>();
options.DocumentFilter<CustomModelDocumentFilter<MyOtherModel>>();
...
}
对于多态 class,您可以使用它们来过滤( 的略微改进版本)。
public class PolymorphismDocumentFilter<T> : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
RegisterSubClasses(context.SchemaRegistry, typeof(T));
}
private static void RegisterSubClasses(ISchemaRegistry schemaRegistry, Type abstractType)
{
const string discriminatorName = "$type";
string friendlyId = abstractType.FriendlyId();
if (!schemaRegistry.Definitions.TryGetValue(friendlyId, out Schema parentSchema))
parentSchema = schemaRegistry.GetOrRegister(abstractType);
// set up a discriminator property (it must be required)
parentSchema.Discriminator = discriminatorName;
parentSchema.Required = new List<string> { discriminatorName };
if (parentSchema.Properties == null)
parentSchema.Properties = new Dictionary<string, Schema>();
if (!parentSchema.Properties.ContainsKey(discriminatorName))
parentSchema.Properties.Add(discriminatorName, new Schema { Type = "string", Default = abstractType.FullName });
// register all subclasses
var derivedTypes = abstractType.GetTypeInfo().Assembly.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));
foreach (var item in derivedTypes)
schemaRegistry.GetOrRegister(item);
}
}
public class PolymorphismSchemaFilter<T> : ISchemaFilter
{
private readonly Lazy<HashSet<Type>> derivedTypes = new Lazy<HashSet<Type>>(Init);
public void Apply(Schema schema, SchemaFilterContext context)
{
if (!derivedTypes.Value.Contains(context.SystemType)) return;
var type = context.SystemType;
var clonedSchema = new Schema
{
Properties = schema.Properties,
Type = schema.Type,
Required = schema.Required
};
// schemaRegistry.Definitions[typeof(T).Name]; does not work correctly in Swashbuckle.AspNetCore
var parentSchema = new Schema { Ref = "#/definitions/" + typeof(T).Name };
var assemblyName = Assembly.GetAssembly(type).GetName();
schema.Discriminator = "$type";
// This is required if you use Microsoft's AutoRest client to generate the JavaScript/TypeScript models
schema.Extensions.Add("x-ms-discriminator-value", $"{type.FullName}, {assemblyName.Name}");
schema.AllOf = new List<Schema> { parentSchema, clonedSchema };
// reset properties for they are included in allOf, should be null but code does not handle it
schema.Properties = new Dictionary<string, Schema>();
}
private static HashSet<Type> Init()
{
var abstractType = typeof(T);
var dTypes = abstractType.GetTypeInfo().Assembly
.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));
var result = new HashSet<Type>();
foreach (var item in dTypes)
result.Add(item);
return result;
}
}
需要两个过滤器。第一个会将您交付的所有 classes 添加到架构中。它还将基础 class 中不存在的属性添加到派生类型的架构中。
第二个过滤器添加了一些属性($type
用于模型 returns 时的序列化)和扩展(用于 Microsoft 的 AutoRest 客户端/生成器)以及添加 allOf
属性到Swagger 模式,这是在使用 swagger-gen 或 AutoRest 生成时创建继承模式所必需的。
注册类似,只是需要成对注册(只需要注册基地class)
// The following lines add polymorphism to the swagger.json schema, so that
// code generators can create properly inheritance hierarchies.
options.DocumentFilter<PolymorphismDocumentFilter<BaseClass>>();
options.SchemaFilter<PolymorphismSchemaFilter<BaseClass>>();
更新 ASP.NET Core 3 和 Swashbuckle.AspNetCore 5.0
public class CustomModelDocumentFilter<T> : IDocumentFilter where T : class
{
public void Apply(OpenApiDocument openapiDoc, DocumentFilterContext context)
{
context.SchemaGenerator.GenerateSchema(typeof(T), context.SchemaRepository);
}
}
PolymorphismDocumentFilter
/PolymorphismSchemaFilter
更新为 Swashbuckle.AspNetCore
5.0
public class PolymorphismDocumentFilter<T> : IDocumentFilter
{
public void Apply(OpenApiDocument openApiDoc, DocumentFilterContext context)
{
RegisterSubClasses(context, typeof(T));
}
private static void RegisterSubClasses(DocumentFilterContext context, Type abstractType)
{
const string discriminatorName = "$type";
var schemaRepository = context.SchemaRepository.Schemas;
var schemaGenerator = context.SchemaGenerator;
if (!schemaRepository.TryGetValue(abstractType.Name, out OpenApiSchema parentSchema))
{
parentSchema = schemaGenerator.GenerateSchema(abstractType, context.SchemaRepository);
}
// set up a discriminator property (it must be required)
parentSchema.Discriminator = new OpenApiDiscriminator { PropertyName = discriminatorName };
parentSchema.Required.Add(discriminatorName);
if (!parentSchema.Properties.ContainsKey(discriminatorName))
parentSchema.Properties.Add(discriminatorName, new OpenApiSchema { Type = "string", Default = new OpenApiString(abstractType.FullName) });
// register all subclasses
var derivedTypes = abstractType.GetTypeInfo().Assembly.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));
foreach (var type in derivedTypes)
schemaGenerator.GenerateSchema(type, context.SchemaRepository);
}
}
和
public class PolymorphismSchemaFilter<T> : ISchemaFilter
{
private readonly Lazy<HashSet<Type>> derivedTypes = new Lazy<HashSet<Type>>(Init);
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
var type = context.ApiModel.Type;
if (!derivedTypes.Value.Contains(type))
return;
var clonedSchema = new OpenApiSchema
{
Properties = schema.Properties,
Type = schema.Type,
Required = schema.Required
};
// schemaRegistry.Definitions[typeof(T).Name]; does not work correctly in SwashBuckle
if(context.SchemaRepository.Schemas.TryGetValue(typeof(T).Name, out OpenApiSchema _))
{
schema.AllOf = new List<OpenApiSchema> {
new OpenApiSchema { Reference = new OpenApiReference { Id = typeof(T).Name, Type = ReferenceType.Schema } },
clonedSchema
};
}
var assemblyName = Assembly.GetAssembly(type).GetName();
schema.Discriminator = new OpenApiDiscriminator { PropertyName = "$type" };
schema.AddExtension("x-ms-discriminator-value", new OpenApiString($"{type.FullName}, {assemblyName.Name}"));
// reset properties for they are included in allOf, should be null but code does not handle it
schema.Properties = new Dictionary<string, OpenApiSchema>();
}
private static HashSet<Type> Init()
{
var abstractType = typeof(T);
var dTypes = abstractType.GetTypeInfo().Assembly
.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));
var result = new HashSet<Type>();
foreach (var item in dTypes)
result.Add(item);
return result;
}
}
我遇到了同样的问题,我的模型没有大摇大摆地出现,因为我的函数的 return 类型具有抽象类型。我修改了上面的答案,这样我就可以将名称空间中的所有内容转储到模型列表中。
在 Startup 中我定义了这个函数:
public class GenericAPI_DocumentFilter<T> : IDocumentFilter where T : class
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
foreach (var t in Assembly.GetExecutingAssembly().GetTypes())
{
if (t.Namespace.Contains("MyAPI") && t.IsClass)
{
var a = t.GetCustomAttribute(typeof(DataContractAttribute));
if (a != null)
{
context.SchemaRegistry.GetOrRegister(t);
}
}
}
}
}
在 swagger 初始化中我添加了一行:
services.AddSwaggerGen(opt =>
{
...
opt.DocumentFilter<GenericAPI_DocumentFilter<object>>();
...
}
回想起来,我在下面(以及其他页面)找到的另一个答案更好,即添加这种属性:
[HttpGet("")]
[ProducesResponseType(typeof(MyResult), (int)System.Net.HttpStatusCode.OK)]
[ProducesResponseType(typeof(ErrorBase), (int)System.Net.HttpStatusCode.NotFound)]
... function definition ...
原因:因为该函数根据不同的情况给出了不同类型的对象,并且通过这些属性您可以指定在哪种情况下返回哪些对象。
例如我可以回馈
return Ok(myresult)
或
return NotFound(myerror)
在我的函数中,基于我是否找到结果。
将 的修改版本用于 .NET Core 3+ 和 Shwashbuckle 5+
这允许您将 [ApiExplorerSettings(GroupName = "my_group")]
属性应用于手动映射的 类(模型、模式),以便仅在特定的单个 swagger 文档中提供它们。
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
public class SwaggerDocumentFilter<T> : IDocumentFilter where T : class
{
/// <summary>
///
/// </summary>
/// <param name="openapiDoc"></param>
/// <param name="context"></param>
public void Apply(OpenApiDocument openapiDoc, DocumentFilterContext context)
{
var DocumentNames = typeof(T).GetCustomAttribute<ApiExplorerSettingsAttribute>();
if (DocumentNames == null || !DocumentNames.GroupName.Any() || context.DocumentName == DocumentNames.GroupName)
{
context.SchemaGenerator.GenerateSchema(typeof(T), context.SchemaRepository);
}
}
}
我正在使用 Swashbuckle 和 ASP.net 内核。它正在制作一个漂亮的网站,底部有一个模型列表。
如何向此列表中添加一个尚未出现的模型?
我在我的一个请求中 return 一个摘要 class,我想列出继承该摘要的所有变体 class。
提前致谢
也许不是最干净的解决方案,但我通过在控制器上方设置 ProducesResponseType
属性实现了同样的效果:
[ProducesResponseType(typeof(object), 200)]
public class FileController : Controller
{
将对象替换为要在模型中显示的对象,并为每个额外的对象创建一个新行。请确保为每个状态码使用不同的状态码,否则它只会显示最后一个。
您可以创建文档过滤器并在全局注册。
public class CustomModelDocumentFilter<T> : IDocumentFilter where T : class
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
context.SchemaRegistry.GetOrRegister(typeof(T));
}
}
然后在您的 Startup
class.
services.AddSwaggerGen(options =>
{
...
options.DocumentFilter<CustomModelDocumentFilter<MyCustomModel>>();
options.DocumentFilter<CustomModelDocumentFilter<MyOtherModel>>();
...
}
对于多态 class,您可以使用它们来过滤(
public class PolymorphismDocumentFilter<T> : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
RegisterSubClasses(context.SchemaRegistry, typeof(T));
}
private static void RegisterSubClasses(ISchemaRegistry schemaRegistry, Type abstractType)
{
const string discriminatorName = "$type";
string friendlyId = abstractType.FriendlyId();
if (!schemaRegistry.Definitions.TryGetValue(friendlyId, out Schema parentSchema))
parentSchema = schemaRegistry.GetOrRegister(abstractType);
// set up a discriminator property (it must be required)
parentSchema.Discriminator = discriminatorName;
parentSchema.Required = new List<string> { discriminatorName };
if (parentSchema.Properties == null)
parentSchema.Properties = new Dictionary<string, Schema>();
if (!parentSchema.Properties.ContainsKey(discriminatorName))
parentSchema.Properties.Add(discriminatorName, new Schema { Type = "string", Default = abstractType.FullName });
// register all subclasses
var derivedTypes = abstractType.GetTypeInfo().Assembly.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));
foreach (var item in derivedTypes)
schemaRegistry.GetOrRegister(item);
}
}
public class PolymorphismSchemaFilter<T> : ISchemaFilter
{
private readonly Lazy<HashSet<Type>> derivedTypes = new Lazy<HashSet<Type>>(Init);
public void Apply(Schema schema, SchemaFilterContext context)
{
if (!derivedTypes.Value.Contains(context.SystemType)) return;
var type = context.SystemType;
var clonedSchema = new Schema
{
Properties = schema.Properties,
Type = schema.Type,
Required = schema.Required
};
// schemaRegistry.Definitions[typeof(T).Name]; does not work correctly in Swashbuckle.AspNetCore
var parentSchema = new Schema { Ref = "#/definitions/" + typeof(T).Name };
var assemblyName = Assembly.GetAssembly(type).GetName();
schema.Discriminator = "$type";
// This is required if you use Microsoft's AutoRest client to generate the JavaScript/TypeScript models
schema.Extensions.Add("x-ms-discriminator-value", $"{type.FullName}, {assemblyName.Name}");
schema.AllOf = new List<Schema> { parentSchema, clonedSchema };
// reset properties for they are included in allOf, should be null but code does not handle it
schema.Properties = new Dictionary<string, Schema>();
}
private static HashSet<Type> Init()
{
var abstractType = typeof(T);
var dTypes = abstractType.GetTypeInfo().Assembly
.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));
var result = new HashSet<Type>();
foreach (var item in dTypes)
result.Add(item);
return result;
}
}
需要两个过滤器。第一个会将您交付的所有 classes 添加到架构中。它还将基础 class 中不存在的属性添加到派生类型的架构中。
第二个过滤器添加了一些属性($type
用于模型 returns 时的序列化)和扩展(用于 Microsoft 的 AutoRest 客户端/生成器)以及添加 allOf
属性到Swagger 模式,这是在使用 swagger-gen 或 AutoRest 生成时创建继承模式所必需的。
注册类似,只是需要成对注册(只需要注册基地class)
// The following lines add polymorphism to the swagger.json schema, so that
// code generators can create properly inheritance hierarchies.
options.DocumentFilter<PolymorphismDocumentFilter<BaseClass>>();
options.SchemaFilter<PolymorphismSchemaFilter<BaseClass>>();
更新 ASP.NET Core 3 和 Swashbuckle.AspNetCore 5.0
public class CustomModelDocumentFilter<T> : IDocumentFilter where T : class
{
public void Apply(OpenApiDocument openapiDoc, DocumentFilterContext context)
{
context.SchemaGenerator.GenerateSchema(typeof(T), context.SchemaRepository);
}
}
PolymorphismDocumentFilter
/PolymorphismSchemaFilter
更新为 Swashbuckle.AspNetCore
5.0
public class PolymorphismDocumentFilter<T> : IDocumentFilter
{
public void Apply(OpenApiDocument openApiDoc, DocumentFilterContext context)
{
RegisterSubClasses(context, typeof(T));
}
private static void RegisterSubClasses(DocumentFilterContext context, Type abstractType)
{
const string discriminatorName = "$type";
var schemaRepository = context.SchemaRepository.Schemas;
var schemaGenerator = context.SchemaGenerator;
if (!schemaRepository.TryGetValue(abstractType.Name, out OpenApiSchema parentSchema))
{
parentSchema = schemaGenerator.GenerateSchema(abstractType, context.SchemaRepository);
}
// set up a discriminator property (it must be required)
parentSchema.Discriminator = new OpenApiDiscriminator { PropertyName = discriminatorName };
parentSchema.Required.Add(discriminatorName);
if (!parentSchema.Properties.ContainsKey(discriminatorName))
parentSchema.Properties.Add(discriminatorName, new OpenApiSchema { Type = "string", Default = new OpenApiString(abstractType.FullName) });
// register all subclasses
var derivedTypes = abstractType.GetTypeInfo().Assembly.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));
foreach (var type in derivedTypes)
schemaGenerator.GenerateSchema(type, context.SchemaRepository);
}
}
和
public class PolymorphismSchemaFilter<T> : ISchemaFilter
{
private readonly Lazy<HashSet<Type>> derivedTypes = new Lazy<HashSet<Type>>(Init);
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
var type = context.ApiModel.Type;
if (!derivedTypes.Value.Contains(type))
return;
var clonedSchema = new OpenApiSchema
{
Properties = schema.Properties,
Type = schema.Type,
Required = schema.Required
};
// schemaRegistry.Definitions[typeof(T).Name]; does not work correctly in SwashBuckle
if(context.SchemaRepository.Schemas.TryGetValue(typeof(T).Name, out OpenApiSchema _))
{
schema.AllOf = new List<OpenApiSchema> {
new OpenApiSchema { Reference = new OpenApiReference { Id = typeof(T).Name, Type = ReferenceType.Schema } },
clonedSchema
};
}
var assemblyName = Assembly.GetAssembly(type).GetName();
schema.Discriminator = new OpenApiDiscriminator { PropertyName = "$type" };
schema.AddExtension("x-ms-discriminator-value", new OpenApiString($"{type.FullName}, {assemblyName.Name}"));
// reset properties for they are included in allOf, should be null but code does not handle it
schema.Properties = new Dictionary<string, OpenApiSchema>();
}
private static HashSet<Type> Init()
{
var abstractType = typeof(T);
var dTypes = abstractType.GetTypeInfo().Assembly
.GetTypes()
.Where(x => abstractType != x && abstractType.IsAssignableFrom(x));
var result = new HashSet<Type>();
foreach (var item in dTypes)
result.Add(item);
return result;
}
}
我遇到了同样的问题,我的模型没有大摇大摆地出现,因为我的函数的 return 类型具有抽象类型。我修改了上面的答案,这样我就可以将名称空间中的所有内容转储到模型列表中。
在 Startup 中我定义了这个函数:
public class GenericAPI_DocumentFilter<T> : IDocumentFilter where T : class
{
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
{
foreach (var t in Assembly.GetExecutingAssembly().GetTypes())
{
if (t.Namespace.Contains("MyAPI") && t.IsClass)
{
var a = t.GetCustomAttribute(typeof(DataContractAttribute));
if (a != null)
{
context.SchemaRegistry.GetOrRegister(t);
}
}
}
}
}
在 swagger 初始化中我添加了一行:
services.AddSwaggerGen(opt =>
{
...
opt.DocumentFilter<GenericAPI_DocumentFilter<object>>();
...
}
回想起来,我在下面(以及其他页面)找到的另一个答案更好,即添加这种属性:
[HttpGet("")]
[ProducesResponseType(typeof(MyResult), (int)System.Net.HttpStatusCode.OK)]
[ProducesResponseType(typeof(ErrorBase), (int)System.Net.HttpStatusCode.NotFound)]
... function definition ...
原因:因为该函数根据不同的情况给出了不同类型的对象,并且通过这些属性您可以指定在哪种情况下返回哪些对象。
例如我可以回馈
return Ok(myresult)
或
return NotFound(myerror)
在我的函数中,基于我是否找到结果。
将
这允许您将 [ApiExplorerSettings(GroupName = "my_group")]
属性应用于手动映射的 类(模型、模式),以便仅在特定的单个 swagger 文档中提供它们。
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
public class SwaggerDocumentFilter<T> : IDocumentFilter where T : class
{
/// <summary>
///
/// </summary>
/// <param name="openapiDoc"></param>
/// <param name="context"></param>
public void Apply(OpenApiDocument openapiDoc, DocumentFilterContext context)
{
var DocumentNames = typeof(T).GetCustomAttribute<ApiExplorerSettingsAttribute>();
if (DocumentNames == null || !DocumentNames.GroupName.Any() || context.DocumentName == DocumentNames.GroupName)
{
context.SchemaGenerator.GenerateSchema(typeof(T), context.SchemaRepository);
}
}
}