【问题标题】:How can I make Swashbuckle respect DataType when generating swagger files?生成 swagger 文件时如何让 Swashbuckle 尊重 DataType?
【发布时间】:2017-04-17 21:39:54
【问题描述】:

我正在使用以下数据合约的更复杂版本,但这应该足以作为示例:

using System;
using System.Runtime.Serialization;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

[DataContract(Namespace = "https://schemas.company.name/api-name/")]
public class Subscription
{
    [DataMember(IsRequired = true)]
    public long SubscriptionID { get; set; }

    [DataMember(IsRequired = true)]
    public long ProductID { get; set; }

    [DataMember(IsRequired = true)]
    public long AccountID { get; set; }

    [DataMember(IsRequired = true), DataType(DataType.Date)]
    public DateTime StartDate { get; set; }

    [DataMember(IsRequired = true), DataType(DataType.Date)]
    public DateTime EndDate { get; set; }
}

Swashbuckle 为上述数据合约生成的 swagger JSON 定义变成了这样:

...
    "Subscription": {
        "required": ["subscriptionID", "productID", "accountID", "startDate", "endDate"],
        "type": "object",
        "properties": {
            "subscriptionID": {
                "format": "int64",
                "type": "integer"
            },
            "productID": {
                "format": "int64",
                "type": "integer"
            },
            "accountID": {
                "format": "int64",
                "type": "integer"
            },
            "startDate": {
                "format": "date-time",
                "type": "string"
            },
            "endDate": {
                "format": "date-time",
                "type": "string"
            }
        }
    },
...

但是,您会注意到 JSON definitions.Subscription.properties.startDate.format"date-time",但 C# 代码中的 DateTypeAttribute 注释是 DataType.Date,而不是 DataType.DateTime

如何让 Swashbuckle 在生成 swagger 文件时尊重 System.ComponentModel.DataAnnotations.DataTypeAttribute?或者更具体地说,使使用[DataType(DataType.Date] 注释的类属性生成format"date" 的招摇?

我希望这是所有类的默认行为,因为我有太多需要硬编码特定类属性的详细信息,并且是使用 Swashbuckle 根据同一命名空间内的其他注释生成 swagger JSON 的重点(如System.ComponentModel.DataAnnotations.StringLengthAttribute)。

我最初的尝试是尝试在我的 Startup.cs 中使用 ISchemaFilter,例如:

    services.AddSwaggerGen(options =>
    {
        ...
        options.SchemaFilter<DataTypeSchemaFilter>();
        ...
    });

过滤器类实现应用的地方:

public class DataTypeSchemaFilter : ISchemaFilter
{
    public void Apply(Schema model, SchemaFilterContext context)
    {
        ???
    }
}

但是,我看不到使用提供的 Schema modelSchemaFilterContext context 参数从过滤器中调查类属性属性的能力。

如前所述,我知道 Swashbuckle 在处理类属性时会查看同一命名空间中的属性,所以我希望有人知道我可以在哪里绑定到 Swashbuckle 并执行类似的任务。

【问题讨论】:

    标签: c# swagger swagger-2.0 swashbuckle


    【解决方案1】:

    我已经编写了下面的代码。本质上,这个想法是将类上的属性名称连接到模式属性名称(schema.properties)。鉴于您可能有自定义序列化程序设置(Camel Case),属性名称的大小写在模式中可能与在类中定义的不同。 我在 SetSchemaDetails 方法中也包含了父模式,以便您可以在需要时在父级添加属性。我们有偶尔使用的自定义必需属性,因此我们需要在父(封闭类)架构级别而不是属性架构级别指定所需属性。

    public class DataAnnotationSchemaFilter : ISchemaFilter
    {
        public void Apply(Schema schema, SchemaFilterContext schemaFilterContext)
        {
            var type = schemaFilterContext.SystemType;
    
            var propertyMappings = type
                .GetProperties()
                .Join(
                    schema.Properties ?? new Dictionary<string, Schema>(),
                    x => x.Name.ToLower(),
                    x => x.Key.ToLower(),
                    (x, y) => new KeyValuePair<PropertyInfo, KeyValuePair<string, Schema>>(x, y))
                .ToList();
    
            foreach (var propertyMapping in propertyMappings)
            {
                var propertyInfo = propertyMapping.Key;
                var propertyNameToSchemaKvp = propertyMapping.Value;
    
                foreach (var attribute in propertyInfo.GetCustomAttributes())
                {
                    SetSchemaDetails(schema, propertyNameToSchemaKvp, propertyInfo, attribute);
                }
            }
        }
    
        private static void SetSchemaDetails(Schema parentSchema, KeyValuePair<string, Schema> propertyNameToSchemaKvp, PropertyInfo propertyInfo, object propertyAttribute)
        {
            var schema = propertyNameToSchemaKvp.Value;
    
            if (propertyAttribute is DataTypeAttribute)
            {
                var dataType = ((DataTypeAttribute)propertyAttribute).DataType;
                if (dataType == DataType.Date)
                {
                    schema.Format = "date";
                    schema.Type = "date";
                }
            }
    
            if (propertyAttribute is ReadOnlyAttribute)
            {
                schema.ReadOnly = ((ReadOnlyAttribute)propertyAttribute).IsReadOnly;
            }
        }
    }
    

    【讨论】:

    • 您能否提供您的 ISchemaFilter 来自哪个命名空间?我在Swashbuckle.SwaggerGen.Generator.ISchemaFilter找到的那个函数原型不一样。
    • Swashbuckle.Swagger.ISchemaFilter。我正在使用 v5.4.0。
    • 已针对 AspNetCore 修复。
    • 谢谢,这正是我所需要的。没有意识到 Type 有这样的属性引用,因此这是我缺少的链接。对于我的具体情况,还需要有schema.Format = "date";,但与自定义属性的通用解决方案相比,这太小了。
    • 固定 schema.Format.
    猜你喜欢
    • 2021-04-13
    • 1970-01-01
    • 1970-01-01
    • 2017-01-05
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 2016-07-11
    • 2019-12-23
    相关资源
    最近更新 更多