gpt4 book ai didi

asp.net-core - 使用 Asp.net core 的 Swashbuckle 如何将模型添加到生成的模型列表中?

转载 作者:行者123 更新时间:2023-12-01 17:56:33 25 4
gpt4 key购买 nike

我正在使用Swashbuckle与 ASP.net 核心。它正在制作一个不错的网站,底部有一个模型列表。

enter image description here

如何将尚未出现的模型添加到此列表中?

我在一个请求中返回一个抽象类,并且我想列出继承该抽象类的所有变体。

提前致谢

最佳答案

您可以创建一个文档过滤器并在全局范围内注册它。

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>>();
...
}

对于多态类,您可以使用它们来过滤(稍微改进的 this answer 版本)。

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);
}
}

针对 Swashbuckle.AspNetCore 5.0 更新了 PolymorphismDocumentFilter/PolymorphismSchemaFilter

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;
}
}

关于asp.net-core - 使用 Asp.net core 的 Swashbuckle 如何将模型添加到生成的模型列表中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49006079/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com