简体   繁体   English

如何使用 Swashbuckle.AspNetCore 在 Swagger 模式中将自定义泛型类型公开为字符串

[英]How to expose a custom generic type as a string in Swagger schema using Swashbuckle.AspNetCore

I have a custom generic type that looks roughly like this:我有一个自定义的泛型类型,大致如下所示:

public struct Foo<T>
{
    public int Value { get; }
    public string Signature { get; }
    public Type Type { get; }
}

This type is is used in request and response bodies and in controller action parameters.此类型用于请求和响应主体以及控制器操作参数中。 Everything is configured so that it's serialized as a string, and it works fine with model binding and JSON serialization.一切都经过配置,以便将其序列化为字符串,并且可以很好地与模型绑定和 JSON 序列化配合使用。 The type has a TypeConverter associated with it, which takes care of converting it to and from a string.该类型有一个与之关联的TypeConverter ,它负责将它与字符串相互转换。

However, the Swagger schema still represents it as an object with 3 properties.但是,Swagger 架构仍将其表示为具有 3 个属性的对象。 The Type property is also expanded, which pulls all the System.Reflection types exposed directly or indirectly by Type . Type属性也被扩展,它拉取所有System.Reflection直接或间接暴露的Type

How can I avoid this and expose my type as a string?如何避免这种情况并将我的类型公开为字符串?


First solution attempted: using MapType尝试的第一个解决方案:使用MapType

I tried to use MapType ;我尝试使用MapType it works fine if I specify the generic type argument, but doesn't work with the open generic type:如果我指定泛型类型参数,它工作正常,但不适用于开放泛型类型:

c.MapType(typeof(Foo<Something>), () => new OpenApiSchema { Type = "string" }); // Works
c.MapType(typeof(Foo<>), () => new OpenApiSchema { Type = "string" }); // Doesn't work

How can I apply the mapping to Foo<T> , for any T ?对于任何T ,如何将映射应用于Foo<T>


Current workaround当前的解决方法

So far the only workaround I have is pretty ugly :到目前为止,我唯一的解决方法是非常丑陋:

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

i am not sure what you are trying to do.我不确定你要做什么。 Because the best thing if i understood your scenario correctly would be to expose one schema definition for each underlying type of the Foo generic type, code then would be something like:因为如果我正确理解你的场景,最好的事情就是为 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.Name}Foo";
                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 };
            }
        }
    }

if you need the other properties as well then include them in the base schema.如果您还需要其他属性,则将它们包含在基本架构中。 This will create a new schema for every type but it should deserialize into your generic type.这将为每种类型创建一个新模式,但它应该反序列化为您的泛型类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Swashbuckle.AspNetCore仅生成带有字符串类型字段的模型 - Swashbuckle.AspNetCore only generating models with fields of type string 在 Swashbuckle.AspNetCore 中,Swagger JSON 和使用 Results.Ok 时生成的 UI 没有内容类型 - In Swashbuckle.AspNetCore, Swagger JSON and UI generated without content type when Results.Ok is used 迁移到 Swashbuckle.AspNetCore 版本 5 时,Swagger UI 中的不记名身份验证 - Bearer authentication in Swagger UI, when migrating to Swashbuckle.AspNetCore version 5 如何在 ASP.NET Core Swagger (Swashbuckle.AspNetCore) 中定义控制器描述? - How to define controller descriptions in ASP.NET Core Swagger (Swashbuckle.AspNetCore)? 数组类型<example>标签不适用于 Swagger (swashbuckle.aspnetcore)</example> - Array types with <example> tag not working with Swagger (swashbuckle.aspnetcore) Swashbuckle.AspNetCore openapi 架构中未正确显示可空属性 - Nullable property is not presented in the Swashbuckle.AspNetCore openapi schema properly AspNetCore Swagger / Swashbuckle如何修改xml模式请求 - AspNetCore Swagger/Swashbuckle how to modify xml schema requests 如何使用Swashbuckle.AspNetCore隐藏响应代码200? - How can I hide response code 200 with Swashbuckle.AspNetCore? 无法从程序集中加载类型“Swashbuckle.AspNetCore.Swagger.SwaggerDocument” - Could not load type 'Swashbuckle.AspNetCore.Swagger.SwaggerDocument' from assembly 无法解析“Swashbuckle.AspNetCore.Swagger.ISwaggerProvider”类型的服务 - Unable to resolve service for type 'Swashbuckle.AspNetCore.Swagger.ISwaggerProvider'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM