swagger 如何包含Display和ErrorMessage装饰器来炫耀生成的文档

agyaoht7  于 2023-01-17  发布在  其他
关注(0)|答案(1)|浏览(173)

我有一个API,我的模型也在那里。我使用.Net核心WEB API和swagger。它们用Required、ErrorMessage和Display来装饰字段。例如:

[Required(ErrorMessage = "FirstName is mandatory")]
[Display(Name = "Service Name")]
public string RouteName { get; set; }

但是由于某种原因,当我使用服务时,swagger.json文件没有Display或ErrorMessage的实现,它只有所需的装饰器实现,这样它会显示:

"RouteHeader": {
    "required": [ "routeName" ],

是否有一种方法/选项,包括这从 Swagger 或我需要转换任何是来自 Swagger ,并把它放在一个单独的“显示模型”,以便这一工作。

ljsrvy3e

ljsrvy3e1#

Swagger JSON文件遵循严格的JSON schema规范,因此您无法真正修改它的结构而不冒使其无效的风险。您可以了解更多关于Swagger JSON文件规范hereJSON Schema的信息。
您可以使用其他属性来包含关于您的模型的额外信息。要扩展在生成的模式中提供的信息,请实现ISchemaFilter接口。它提供了一个Apply()方法,该方法为将包含在结果Swagger JSON文件中的每个模型类型(schema)调用。通常,这些类型基于控制器方法中使用的请求和响应类型。

public class ErrorMessageSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        // Skip if schema has no required properties.
        if (!schema.Required.Any())
        {
            return;
        }

        var propertyWithAttribute = context.Type
            .GetProperties()
            .Select(p => (p.Name, p.GetCustomAttribute<RequiredAttribute>()))
            .Where(tuple => tuple.Item2 != null)
            .ToList();

        foreach (var (name, required) in propertyWithAttribute)
        {
            // Will throw for property name of length 1...
            var pascalCaseName = char.ToLowerInvariant(name[0]) + name[1..];

            if (schema.Properties.TryGetValue(pascalCaseName, out var property))
            {
                property.Properties.Add("RequiredErrorMessage", new OpenApiSchema
                {
                    Title = required.ErrorMessage
                });
            }
        }
    }
}

显示名称筛选器类似于:

public class DisplayNameSchemaFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        var propertyWithAttribute = context.Type
            .GetProperties()
            .Select(p => (p.Name, p.GetCustomAttribute<DisplayAttribute>()))
            .Where(tuple => tuple.Item2 != null)
            .ToList();

        foreach (var (name, required) in propertyWithAttribute)
        {
            // Will throw for property name of length 1...
            var pascalCaseName = char.ToLowerInvariant(name[0]) + name[1..];

            if (schema.Properties.TryGetValue(pascalCaseName, out var property))
            {
                property.Properties.Add("DisplayName", new OpenApiSchema
                {
                    Title = required.Name
                });
            }
        }
    }
}

ConfigureServices()方法中注册启动时的模式过滤器:

services.AddSwaggerGen(opts =>
{
    opts.SchemaFilter<ErrorMessageSchemaFilter>();
    opts.SchemaFilter<DisplayNameSchemaFilter>();
});
结果示例

给定一个简单的Weather模型:

public class Weather
{
    public string City { get; set; }

    [Required(ErrorMessage = "Temperature is required.")]
    public int Temperature { get; set; }

    [Display(Name = "Is it cloudy?")]
    public bool IsCloudy { get; set; }
}

它将在swagger.json中生成这段模式(为简洁起见,删除了一些部分):

{
"components": {
    "schemas": {
      "Weather": {
        "required": [
          "temperature"
        ],
        "type": "object",
        "properties": {
          "city": {
            "type": "string",
            "nullable": true
          },
          "temperature": {
            "type": "integer",
            "properties": {
              "RequiredErrorMessage": {
                "title": "Temperature is required."
              }
            },
            "format": "int32"
          },
          "isCloudy": {
            "type": "boolean",
            "properties": {
              "DisplayName": {
                "title": "Is it cloudy?"
              }
            }
          }
        },
        "additionalProperties": false
      }
    }
  }
}

结果在Swagger UI中看起来相当平庸,所以可以尝试其他属性,这些属性可以更好地显示在UI中。

相关问题