如何使用 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&lt;T&gt;


当前解决方法

到目前为止,我唯一的解决方法很丑:

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 提交?

如何使用laravel保存所有行数据每个行名或相等

如何使用 Math.Net 连接矩阵。如何使用 Math.Net 调用特定的行或列?

WSARecv 如何使用 lpOverlapped?如何手动发出事件信号?