Asp.net-Core
使用 Swashbuckle for Asp.net core 如何將模型添加到生成的模型列表中?
我正在使用帶有 ASP.net 核心的Swashbuckle 。它正在製作一個很好的網站,底部有一個模型列表。
如何將尚未出現的模型添加到此列表中?
我在我的一個請求中返回了一個抽像類,我想列出繼承該抽像類的所有變體。
提前致謝
您可以創建一個文件過濾器並在全域範圍內註冊它。
public class CustomModelDocumentFilter<T> : IDocumentFilter where T : class { public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context) { context.SchemaRegistry.GetOrRegister(typeof(T)); } }然後在你的
Startup班級註冊。services.AddSwaggerGen(options => { ... options.DocumentFilter<CustomModelDocumentFilter<MyCustomModel>(); options.DocumentFilter<CustomModelDocumentFilter<MyOtherModel>(); ... }對於多態類,您可以使用這些過濾器(此答案的略微改進版本)。
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; } }需要兩個過濾器。第一個會將您傳遞的所有類添加到模式中。它還將基類中不存在的屬性添加到派生類型的架構中。
第二個過濾器添加了一些屬性(
$type用於模型返回時的序列化)和擴展(用於 Microsoft 的 AutoRest 客戶端/生成器)以及將allOf屬性添加到 Swagger 架構中,這是在使用 swagger 生成時創建繼承架構所必需的- gen 或 AutoRest。註冊類似,只是需要成對註冊(只需要註冊基類)
// 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.AspNetCore5.0public 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; } }
