我正在处理以下数据合同的更复杂版本,但这应该足以作为示例:
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
如何在生成swagger文件时让Swashbuckle尊重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 model
和SchemaFilterContext context
参数调查过滤器中的类属性属性。
如前所述,我知道Swashbuckle在处理类属性时会查看同一命名空间中的属性,因此我希望有人知道我可以在哪里与Swashbuckle绑定并执行类似的任务。
答案 0 :(得分:2)
我写了下面的代码。本质上,您的想法是将类的属性名称加入到架构属性名称(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;
}
}
}