如何使用 Swashbuckle.AspNetCore 在 Swagger 模式中将自定义泛型类型公开为字符串
Posted
技术标签:
【中文标题】如何使用 Swashbuckle.AspNetCore 在 Swagger 模式中将自定义泛型类型公开为字符串【英文标题】:How to expose a custom generic type as a string in Swagger schema using Swashbuckle.AspNetCore 【发布时间】:2020-03-26 10:28:17 【问题描述】:我有一个自定义泛型类型,大致如下:
public struct Foo<T>
public int Value get;
public string Signature get;
public Type Type get;
此类型用于请求和响应主体以及控制器操作参数中。一切都被配置为序列化为字符串,并且可以很好地与模型绑定和 JSON 序列化配合使用。该类型有一个与之关联的TypeConverter
,它负责将其转换为字符串。
但是,Swagger 模式仍将其表示为具有 3 个属性的对象。 Type
属性也被扩展,它拉取了所有由Type
直接或间接暴露的System.Reflection
类型。
如何避免这种情况并将我的类型公开为字符串?
尝试的第一个解决方案:使用MapType
我尝试使用MapType
;如果我指定泛型类型参数,它可以正常工作,但不适用于开放的泛型类型:
c.MapType(typeof(Foo<Something>), () => new OpenApiSchema Type = "string" ); // Works
c.MapType(typeof(Foo<>), () => new OpenApiSchema Type = "string" ); // Doesn't work
对于任何T
,我如何将映射应用到Foo<T>
?
当前解决方法
到目前为止,我唯一的解决方法很丑:
class SchemaFilter : ISchemaFilter
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
if (context.Type is Type type &&
type.IsGenericType &&
!type.IsGenericTypeDefinition &&
type.GetGenericTypeDefinition() == typeof(Foo<>))
schema.Type = "string";
schema.Properties.Clear();
else if (context.Type?.FullName.StartsWith("System.", StringComparison.Ordinal) is true
&& context.SchemaRepository.TryGetIdFor(context.Type, out var schemaId))
DocFilter.SchemaIdsToRemove.Add(schemaId);
class DocFilter : IDocumentFilter
public static readonly HashSet<string> SchemaIdsToRemove = new HashSet<string>();
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
foreach (var schemaId in SchemaIdsToRemove)
swaggerDoc.Components.Schemas.Remove(schemaId);
【问题讨论】:
是的,丑陋的自定义泛型变得丑陋ISchemaFilter
...你需要那个泛型类型吗?如果它最终映射到一个字符串,为什么它不仅仅是一个字符串......或者 SwaggerResponse 是一个更干净的替代品[SwaggerResponse(201, "The product was created", typeof(Product))]
我确实需要它是通用的。它携带我在过滤器中用于验证值的类型信息。
您希望它是通用的,但它不需要...将其设为字符串,然后解析/验证您需要的内容...并记录使用I...Filter
解决方案在代码中也以“丑陋”的方式github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/…
【参考方案1】:
我不确定您要做什么。因为如果我正确理解您的场景,最好的办法是为 Foo 泛型类型的每个基础类型公开一个模式定义,那么代码将类似于:
public class FooSchemaFilter : ISchemaFilter
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
if (context.Type.IsGenericType && context.Type.GetGenericTypeDefinition() == typeof(Foo<>))
var argumentType = context.Type.GetGenericArguments().First();
var argumentSchema = context.SchemaGenerator.GenerateSchema(argumentType, context.SchemaRepository);
var baseSchemaName = $"argumentType.NameFoo";
var baseSchema = new OpenApiSchema()
Required = new SortedSet<string>() "type" ,
Type = "object",
Properties = new Dictionary<string, OpenApiSchema>
"type", argumentSchema
;
context.SchemaRepository.AddDefinition(baseSchemaName, baseSchema);
schema.Type = "string";
schema.Reference = new OpenApiReference Id = $"baseSchemaName", Type = ReferenceType.Schema ;
如果您还需要其他属性,则将它们包含在基本架构中。 这将为每种类型创建一个新架构,但它应该反序列化为您的泛型类型。
【讨论】:
以上是关于如何使用 Swashbuckle.AspNetCore 在 Swagger 模式中将自定义泛型类型公开为字符串的主要内容,如果未能解决你的问题,请参考以下文章
如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]
如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?