使用 Swashbuckle 5.x 在通用 T 参数引用上指定 nullable = true 属性
Using Swashbuckle 5.x specify nullable = true on a Generic T Parameter reference property
我最近将我的 API 升级到 .net core 3.1 服务器,使用带有 newtonsoft json nuget 的 Swashbuckle 5,它生成一个 openapi 3 模式。然后我使用 NSwag 生成 C# API。以前我有一个带有 swashbuckle 4 的 .net core 2.2 服务器,生成一个 swagger 2.0 api 模式。
我有一个针对所有响应的通用响应 class,其中包含一些关于响应的元数据,例如状态代码和消息,以及包含响应内容的通用类型 T 的有效负载 属性 .
当响应是错误代码时,我将有效载荷属性设置为空。我正在努力寻找一种方法来定义我的 api,以便 swashbuckle 和 NSwag 组合产生一个 C# api,这将允许有效负载 属性 在反序列化时为 null。 (swagger 2.0 / swashbuckle 4 工作正常)。
尽可能地尝试,Payload 属性 总是得到注释 [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.DisallowNull...]
和 [System.ComponentModel.DataAnnotations.Required]
注释。
据我了解,open API 3 现在允许“$ref”属性在架构定义中具有 "nullable": true 属性。如果我在创建后手动将其添加到我的定义中,NSwag 会正确删除 CSharp api 中的 Required 属性,并将 Json属性 Required 属性设置为 "Default" (不需要)而不是 "DisallowNull".
但是,我标记负载 属性 的任何内容都不会导致 nullable: true 出现在我的架构 json 定义中。
我要的是这个:
"properties": {
"payload": {
"nullable": true,
"$ref": "#/components/schemas/VisualService.Client.Models.MyResultClass"
},
我得到的是:
"properties": {
"payload": {
"$ref": "#/components/schemas/VisualService.Client.Models.MyResultClass"
},
在引用的 $ref 对象本身的定义上设置 "nullable"=true 也是可行的。我也找不到办法做到这一点。
我尝试了以下补救措施,但没有成功。
以不同的方式用 Json属性 标记 dto class 中的 属性:
[JsonProperty(Required = Required.AllowNull)]
public T Payload { get; set; }
[AllowNull]
public T Payload { get; set; }
[MaybeNull]
public T Payload { get; set; }
试图告诉 Swashbuckle / Newtonsoft 使用我的自定义 Json 解析器,如 this github issue 中所述 - 似乎不服从
services.AddControllers()
.AddNewtonsoftJson(options =>
{ options.SerializerSettings.ContractResolver = MyCustomResolver();
我创建了自己的自定义属性和过滤器以尝试将 属性 设置为可为 nullable
[NullableGenericProperty]
public T Payload { get; set; }
[AttributeUsage(AttributeTargets.Property)]
public class NullableGenericPropertyAttribute : Attribute
{
}
public class SwaggerNullablePayloadFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (schema?.Properties == null || context?.Type == null)
return;
var nullableGenericProperties = context.Type.GetProperties()
.Where(t =>
t.GetCustomAttribute<NullableGenericPropertyAttribute>()
!= null);
foreach (var excludedProperty in nullableGenericProperties)
{
if (schema.Properties.ContainsKey(excludedProperty.Name.ToLowerInvariant()))
{
var prop = schema.Properties[excludedProperty.Name.ToLowerInvariant()];
prop.Nullable = true;
prop.Required = new HashSet<string>() { "false" };
}
}
}
}
我在这方面取得了小成功,因为添加了 prop.Nullable = true;导致属性 [System.ComponentModel.DataAnnotations.Required]
从 c# api 中删除。但是,[Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.DisallowNull...]
仍然存在,所以它并没有太大帮助。我添加了 prop.Required = new HashSet<string>() { "false" };
作为额外的尝试,但它似乎没有做任何事情。
我可以再次降级到 .net core 2.2 / swashbuckle 4,但是 2.2 没有长期支持,我想尽可能留在 3.1。我也可以每次都在生成的 API 客户端上进行查找和替换,但我不想每次重新生成 api 时都必须手动记住执行此操作,一天可能发生几次在开发周期中。
我有一个 hacky 解决方法 - 我正在拦截 json 响应并在我的服务器上需要它的地方添加 "nullable" = true
,方法是在响应上使用正则表达式匹配Body json 字符串,在将其提供给客户端之前。虽然它真的很 hacky,如果存在的话,我想要一种原生的方式来做到这一点。
感谢任何帮助!
有一个设置可以完成此操作:
UseAllOfToExtendReferenceSchemas
它将模式更改为此,nswag 可以使用它来允许 $ref 属性为空值。
"payload": {
"required": [
"false"
],
"allOf": [
{
"$ref": "#/components/schemas/MyResultClass"
}
],
"nullable": true
},
这样使用:
_ = services.AddSwaggerGen(setup =>
{
setup.SwaggerDoc("v1", new OpenApiInfo { Title = AppConst.SwaggerTitle, Version = "v1" });
setup.UseAllOfToExtendReferenceSchemas();
...
我最近将我的 API 升级到 .net core 3.1 服务器,使用带有 newtonsoft json nuget 的 Swashbuckle 5,它生成一个 openapi 3 模式。然后我使用 NSwag 生成 C# API。以前我有一个带有 swashbuckle 4 的 .net core 2.2 服务器,生成一个 swagger 2.0 api 模式。
我有一个针对所有响应的通用响应 class,其中包含一些关于响应的元数据,例如状态代码和消息,以及包含响应内容的通用类型 T 的有效负载 属性 .
当响应是错误代码时,我将有效载荷属性设置为空。我正在努力寻找一种方法来定义我的 api,以便 swashbuckle 和 NSwag 组合产生一个 C# api,这将允许有效负载 属性 在反序列化时为 null。 (swagger 2.0 / swashbuckle 4 工作正常)。
尽可能地尝试,Payload 属性 总是得到注释 [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.DisallowNull...]
和 [System.ComponentModel.DataAnnotations.Required]
注释。
据我了解,open API 3 现在允许“$ref”属性在架构定义中具有 "nullable": true 属性。如果我在创建后手动将其添加到我的定义中,NSwag 会正确删除 CSharp api 中的 Required 属性,并将 Json属性 Required 属性设置为 "Default" (不需要)而不是 "DisallowNull".
但是,我标记负载 属性 的任何内容都不会导致 nullable: true 出现在我的架构 json 定义中。
我要的是这个:
"properties": {
"payload": {
"nullable": true,
"$ref": "#/components/schemas/VisualService.Client.Models.MyResultClass"
},
我得到的是:
"properties": {
"payload": {
"$ref": "#/components/schemas/VisualService.Client.Models.MyResultClass"
},
在引用的 $ref 对象本身的定义上设置 "nullable"=true 也是可行的。我也找不到办法做到这一点。
我尝试了以下补救措施,但没有成功。
以不同的方式用 Json属性 标记 dto class 中的 属性:
[JsonProperty(Required = Required.AllowNull)] public T Payload { get; set; } [AllowNull] public T Payload { get; set; } [MaybeNull] public T Payload { get; set; }
试图告诉 Swashbuckle / Newtonsoft 使用我的自定义 Json 解析器,如 this github issue 中所述 - 似乎不服从
services.AddControllers()
.AddNewtonsoftJson(options =>
{ options.SerializerSettings.ContractResolver = MyCustomResolver();
我创建了自己的自定义属性和过滤器以尝试将 属性 设置为可为 nullable
[NullableGenericProperty] public T Payload { get; set; }
[AttributeUsage(AttributeTargets.Property)]
public class NullableGenericPropertyAttribute : Attribute
{
}
public class SwaggerNullablePayloadFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (schema?.Properties == null || context?.Type == null)
return;
var nullableGenericProperties = context.Type.GetProperties()
.Where(t =>
t.GetCustomAttribute<NullableGenericPropertyAttribute>()
!= null);
foreach (var excludedProperty in nullableGenericProperties)
{
if (schema.Properties.ContainsKey(excludedProperty.Name.ToLowerInvariant()))
{
var prop = schema.Properties[excludedProperty.Name.ToLowerInvariant()];
prop.Nullable = true;
prop.Required = new HashSet<string>() { "false" };
}
}
}
}
我在这方面取得了小成功,因为添加了 prop.Nullable = true;导致属性 [System.ComponentModel.DataAnnotations.Required]
从 c# api 中删除。但是,[Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.DisallowNull...]
仍然存在,所以它并没有太大帮助。我添加了 prop.Required = new HashSet<string>() { "false" };
作为额外的尝试,但它似乎没有做任何事情。
我可以再次降级到 .net core 2.2 / swashbuckle 4,但是 2.2 没有长期支持,我想尽可能留在 3.1。我也可以每次都在生成的 API 客户端上进行查找和替换,但我不想每次重新生成 api 时都必须手动记住执行此操作,一天可能发生几次在开发周期中。
我有一个 hacky 解决方法 - 我正在拦截 json 响应并在我的服务器上需要它的地方添加 "nullable" = true
,方法是在响应上使用正则表达式匹配Body json 字符串,在将其提供给客户端之前。虽然它真的很 hacky,如果存在的话,我想要一种原生的方式来做到这一点。
感谢任何帮助!
有一个设置可以完成此操作:
UseAllOfToExtendReferenceSchemas
它将模式更改为此,nswag 可以使用它来允许 $ref 属性为空值。
"payload": {
"required": [
"false"
],
"allOf": [
{
"$ref": "#/components/schemas/MyResultClass"
}
],
"nullable": true
},
这样使用:
_ = services.AddSwaggerGen(setup =>
{
setup.SwaggerDoc("v1", new OpenApiInfo { Title = AppConst.SwaggerTitle, Version = "v1" });
setup.UseAllOfToExtendReferenceSchemas();
...