使用 Swashbuckle 5.x 在通用 T 参数引用属性上指定 nullable = true [英] Using Swashbuckle 5.x specify nullable = true on a Generic T Parameter reference property

查看:113
本文介绍了使用 Swashbuckle 5.x 在通用 T 参数引用属性上指定 nullable = true的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近使用 Swashbuckle 5 和 newtonsoft json nuget 将我的 API 升级到了 .net core 3.1 服务器,它生成了一个 openapi 3 架构.然后我使用 NSwag 生成一个 C# API.以前我有一个带有 swashbuckle 4 的 .net core 2.2 服务器,生成了一个 swagger 2.0 api 模式.

I recently upgraded my API to a .net core 3.1 server using Swashbuckle 5 with the newtonsoft json nuget, which produces an openapi 3 schema. I then use NSwag to generate a C# API. Previously I had a .net core 2.2 server with swashbuckle 4, producing a swagger 2.0 api schema.

我有一个适用于所有响应的通用响应类,其中包含有关响应的一些元数据,例如状态代码和消息,以及包含响应内容的通用类型 T 的 Payload 属性.

I have a generic response class for all responses, containing some metadata about the response like status code and a message, plus a Payload property of Generic type T containing the meat of the response.

当响应是错误代码时,我将有效负载属性设置为 null.我正在努力寻找一种定义我的 api 的方法,以便 swashbuckle 和 NSwag 结合产生一个 C# api,它将允许有效载荷属性在反序列化时为空.(swagger 2.0/swashbuckle 4 没有问题).

When the response is an error code, I set the payload property to null. I am struggling to find a way to define my api so that swashbuckle and NSwag combined produce a C# api that will allow the payload property to be null on deserialization. (swagger 2.0 / swashbuckle 4 worked without issue).

尽我所能,Payload 属性总是得到注释 [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.DisallowNull...][System.ComponentModel.DataAnnotations.Required] 注释.

Try as I might, the Payload property always gets the annotation [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.DisallowNull...] and the [System.ComponentModel.DataAnnotations.Required] annotation.

据我所知,开放 API 3 现在允许 "$ref" 属性在架构定义中具有 "nullable": true 属性.如果我在创建后手动将其添加到我的定义中,NSwag 会正确删除 CSharp api 中的必需属性,并将 JsonProperty 必需属性设置为默认"(非必需)而不是DisallowNull".
但是,我标记有效负载属性的任何内容都不会导致 nullable: true 出现在我的架构 json 定义中.

As I understand it, open API 3 now allows "$ref" properties to have the "nullable": true attribute in the schema definition. If I add this manually to my definition after it is created, NSwag correctly removes the Required attribute in the CSharp api and crucially sets the JsonProperty Required attribute to be "Default" (not required) instead of "DisallowNull".
However, nothing that I mark up the payload property with causes the nullable: true to appear in my schema json definition.

我想要的是这个:

"properties": {
          "payload": {
            "nullable": true, 
            "$ref": "#/components/schemas/VisualService.Client.Models.MyResultClass"
          },

我得到的是这个:

"properties": {
          "payload": {
            "$ref": "#/components/schemas/VisualService.Client.Models.MyResultClass"
          },

在被引用的 $ref 对象本身的定义上设置nullable"=true 也是可行的.我也找不到办法做到这一点.

What would also work is setting the "nullable"=true on the definition of the referenced $ref object itself. I can't find a way to do this either.

我尝试了以下补救措施,但没有成功.

I have tried the following remedies, to no success.

  1. 使用 JsonProperty 以不同方式标记 dto 类中的属性:

  1. Marking up the property in the dto class with JsonProperty in different ways:

[JsonProperty(Required = Required.AllowNull)]
public T Payload { get; set; }

[AllowNull]
public T Payload { get; set; }

[MaybeNull]
public T Payload { get; set; }

  • 试图告诉 Swashbuckle/Newtonsoft 使用我在 this github 中描述的自定义 Json 解析器问题-似乎不服从

        services.AddControllers()
                            .AddNewtonsoftJson(options =>
                            {                        options.SerializerSettings.ContractResolver = MyCustomResolver();
    
    

    1. 我创建了自己的自定义属性和过滤器以尝试将该属性设置为可为空

    1. I created my own custom attribute and filter to try to set the property as 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() { "false" }; 作为额外的尝试,但它似乎没有做任何事情.

    I had minor success with this one, in that adding the prop.Nullable = true; caused the attribute[System.ComponentModel.DataAnnotations.Required] to be removed from the c# api. However, the [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.DisallowNull...] still remained, so it didn't help that much. I added prop.Required = new HashSet<string>() { "false" }; as an additional try, but it doesn't seem to do anything.

    我可以再次降级到 .net core 2.2/swashbuckle 4,但 2.2 已失去长期支持,如果可能的话,我想保持在 3.1.我也可以每次都在生成的 API 客户端上进行查找和替换,但我不想每次重新生成 api 时都必须手动记住执行此操作,这在开发周期中每天可能会发生几次.

    I could downgrade to .net core 2.2 / swashbuckle 4 again but 2.2 is out of long term support and I want to stay at 3.1 if at all possible. I could also do a find and replace on my generated API client every time but I don't want to have to manually remember to do it every time I regenerate the api which can be several times a day in development cycles.

    我有一个 hacky 解决方法 - 即我正在拦截 json 响应并在我的服务器上需要它的地方添加 "nullable" = true,方法是在我的服务器上使用正则表达式匹配响应正文 json 字符串,在将其提供给客户端之前.虽然它真的很hacky,如果它存在,我想要一种本地方式来做到这一点.

    I've got a hacky workaround - which is that I'm intercepting the json response and adding the "nullable" = true on my server where it's needed, by using a regex match on the response Body json string, before serving it to the client. It's really hacky though and I'd like a native way to do this if it exists.

    感谢所有帮助!

    推荐答案

    有一个设置可以做到这一点:

    There is a setting that accomplishes this:

    UseAllOfToExtendReferenceSchemas 
    

    它将架构更改为此,nswag 可以使用它来允许 $ref 属性为空.

    It changes the schema to this, which nswag can use to allow nulls for $ref properties.

      "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();
                ...
    

    这篇关于使用 Swashbuckle 5.x 在通用 T 参数引用属性上指定 nullable = true的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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