使用serializeAsV2使用向后兼容的枚举生成swagger.json [英] generating swagger.json with backwardly compatible enum using serializeAsV2

查看:347
本文介绍了使用serializeAsV2使用向后兼容的枚举生成swagger.json的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我将我的api从netcore2.1升级到了netcore3.1

Recently I upgraded my api from netcore2.1 to netcore3.1

我希望不要求api用户重写其客户端.

I was hoping not to ask the api users to re-write their client.

因此,我希望我需要swagger.json向后兼容.

Thus I expect I need the swagger.json to be backwardly compatible.

在旧的swagger.json中,枚举看起来像

In the old swagger.json an enum would look like

但是现在看起来像

我正在使用Swashbuckle.AspNetCore 5.2.1

I am using Swashbuckle.AspNetCore 5.2.1

我有一个名为AddSwaggerDocumentation的扩展名,它调用了

I have an extension called AddSwaggerDocumentation and it calls

services.AddSwaggerGen(c =>
            {
            c.EnableAnnotations();
            c.ParameterFilter<SwaggerEnumParameterFilter>();
            c.SchemaFilter<SwaggerEnumFilter>();

其中

public class SwaggerEnumFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema model, SchemaFilterContext context)
    {
        if (context.Type.IsEnum)
        {
            var values = Enum.GetValues(context.Type);
            var valuesArr = new OpenApiArray();
            foreach (var value in values)
            {
                var item = new OpenApiObject
                {
                    ["name"] = new OpenApiString(Enum.GetName(context.Type, value)),
                    ["value"] = new OpenApiString(value.ToString())
                };

                valuesArr.Add(item);
            }
            model.Extensions.Add("x-ms-enum", new OpenApiObject
            {
                ["name"] = new OpenApiString(context.Type.Name),
                ["modelAsString"] = new OpenApiBoolean(true),
                ["values"] = valuesArr
            });
        }

    }
}

我也有

    public static IApplicationBuilder UseSwaggerDocumentation(this IApplicationBuilder app)
    {
        var basePath = "/v1";
        app.UseSwagger(c =>
        {
            c.RouteTemplate = "api-docs/{documentName}/swagger.json";
            c.SerializeAsV2 = true;
            c.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
            {
                swaggerDoc.Servers = new List<OpenApiServer> { new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}{basePath}" } };
            });
        });

        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("./v1/swagger.json", "Versioned API v1.0");  //
            c.RoutePrefix = "api-docs";
        });

        return app;
    }

public class SwaggerEnumParameterFilter : IParameterFilter
{

    public void Apply(OpenApiParameter parameter, ParameterFilterContext context)
    {
        var type = context.ApiParameterDescription.Type;

        if (type.IsEnum)
        {
            var values = Enum.GetValues(type);
            var valuesArr = new OpenApiArray();
            foreach (var value in values)
            {
                var item = new OpenApiObject
                {
                    ["name"] = new OpenApiString(Enum.GetName(type, value)),
                    ["value"] = new OpenApiString(value.ToString())
                };

                valuesArr.Add(item);
            }
            parameter.Extensions.Add("x-ms-enum", new OpenApiObject
            {
                ["name"] = new OpenApiString(type.Name),
                ["modelAsString"] = new OpenApiBoolean(true),
                ["values"] = valuesArr
            });
        }
    }
}

public static class SwaggerGenOptionsExtensions
{
    public static SwaggerGenOptions RegisterEnumSchemas(this SwaggerGenOptions options, Assembly assembly, string enumsNamespace)
    {
        var enums = from t in assembly.GetTypes()
            where t.IsEnum && t.Namespace == enumsNamespace
            select t;

        foreach (var enumerate in enums)
        {
            var nullableEnumerate = typeof(Nullable<>).MakeGenericType(enumerate);

            MapEnumType(options, enumerate, false);
            MapEnumType(options, nullableEnumerate, true);
        }

        return options;
    }

    private static void MapEnumType(SwaggerGenOptions options, Type enumerate, bool nullable)
    {
        var underlyingEnum = nullable ? Nullable.GetUnderlyingType(enumerate) : enumerate;

        options.MapType(enumerate, () => new OpenApiSchema
        {
            Type = "string",
            Enum = underlyingEnum.GetEnumNames().Select(name => new OpenApiString(name)).Cast<IOpenApiAny>().ToList(),
            Nullable = nullable
        });
    }
}

[更新]

尝试BlueJayke的建议

Trying BlueJayke's suggestion

推荐答案

是的yeash yeash ...只需执行以下操作即可:

yeash yeash yeash... just do something like the following:

public class EnumDocumentFilter : IDocumentFilter {
    /// <inheritdoc />
    public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context) {
        // add enum descriptions to result models
        foreach (var schemaDictionaryItem in swaggerDoc.Definitions) {
            var schema = schemaDictionaryItem.Value;
            foreach (var propertyDictionaryItem in schema.Properties) {
                var property = propertyDictionaryItem.Value;
                var propertyEnums = property.Enum;
                if (propertyEnums != null && propertyEnums.Count > 0) {
                    property.Description += DescribeEnum(propertyEnums);
                }
            }
        }

        if (swaggerDoc.Paths.Count <= 0) return;

        // add enum descriptions to input parameters
        foreach (var pathItem in swaggerDoc.Paths.Values) {
            DescribeEnumParameters(pathItem.Parameters);

            // head, patch, options, delete left out
            var possibleParameterisedOperations = new List<Operation> {pathItem.Get, pathItem.Post, pathItem.Put};
            possibleParameterisedOperations.FindAll(x => x != null)
                .ForEach(x => DescribeEnumParameters(x.Parameters));
        }
    }

    private static void DescribeEnumParameters(IList<IParameter> parameters) {
        if (parameters == null) return;

        foreach (var param in parameters) {
            if (param is NonBodyParameter nbParam && nbParam.Enum?.Any() == true) {
                param.Description += DescribeEnum(nbParam.Enum);
            } else if (param.Extensions.ContainsKey("enum") && param.Extensions["enum"] is IList<object> paramEnums &&
                paramEnums.Count > 0) {
                param.Description += DescribeEnum(paramEnums);
            }
        }
    }

    private static string DescribeEnum(IEnumerable<object> enums) {
        var enumDescriptions = new List<string>();
        Type type = null;
        foreach (var enumOption in enums) {
            if (type == null) type = enumOption.GetType();
            enumDescriptions.Add($"{Convert.ChangeType(enumOption, type.GetEnumUnderlyingType())} = {Enum.GetName(type, enumOption)}");
        }

        return $"{Environment.NewLine}{string.Join(Environment.NewLine, enumDescriptions)}";
    }
}

别忘了

public class EnumTypeSchemaFilter : ISchemaFilter {
    public void Apply(Schema schema, SchemaFilterContext context) {
        var typeInfo = context.SystemType.GetTypeInfo();

        if (typeInfo.IsEnum) {
            schema.Extensions.Add(
                "x-ms-enum",
                new {
                    name = typeInfo.Name,
                    modelAsString = false
                });
        }
    }
}

和参数文件:

public class AutoRestParameterFilter : IParameterFilter
{
    public void Apply(IParameter parameter, ParameterFilterContext context)
    {
        var type = context.ApiParameterDescription.Type;

        if (type.IsEnum)
            parameter.Extensions.Add( "x-ms-enum", new { name = type.Name, modelAsString = false });
    }
}

希望可以帮助清理问题

这篇关于使用serializeAsV2使用向后兼容的枚举生成swagger.json的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆