Используя Swashbuckle 5.x, укажите nullable = true в свойстве ссылки Generi c T Parameter - PullRequest
1 голос
/ 17 июня 2020

Недавно я обновил свой API до сервера. net core 3.1, используя Swashbuckle 5 с nuget json newtonsoft, который создает схему openapi 3. Затем я использую NSwag для создания API C#. Раньше у меня был сервер. net core 2.2 с функцией swashbuckle 4, который создавал схему api swagger 2.0.

У меня есть общий класс ответа c для всех ответов, содержащий некоторые метаданные об ответе, такие как код состояния и сообщение, а также свойство Payload типа Generi c T, содержащее основную часть ответа.

Когда ответом является код ошибки, я устанавливаю свойство payload равным null. Я изо всех сил пытаюсь найти способ определить свой api, чтобы swashbuckle и NSwag вместе создавали C# api, который позволит свойству полезной нагрузки быть нулевым при десериализации. (swagger 2.0 / swashbuckle 4 работали без проблем).

Как бы я ни старался, свойство Payload всегда получает аннотацию [Newtonsoft.Json.JsonProperty("payload", Required = Newtonsoft.Json.Required.DisallowNull...] и аннотацию [System.ComponentModel.DataAnnotations.Required].

Насколько я понимаю, открытый API 3 теперь позволяет свойствам «$ ref» иметь атрибут «nullable»: true в определении схемы. Если я добавлю это вручную к своему определению после его создания, NSwag правильно удалит атрибут Required в CSharp api и существенно установит для атрибута JsonProperty 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"
          },

Что также будет работать, так это установка "nullable" = true на определение самого объекта $ ref, на который имеется ссылка. Я тоже не могу найти способ сделать это.

Я пробовал следующие средства, но безуспешно.

  1. Разметка свойства в классе dto с помощью JsonProperty по-разному:

    [JsonProperty(Required = Required.AllowNull)]
    public T Payload { get; set; }
    
    [AllowNull]
    public T Payload { get; set; }
    
    [MaybeNull]
    public T Payload { get; set; }
    
  2. Попытка сказать Swashbuckle / Newtonsoft использовать мой собственный Json Resolver, как описано в , эта проблема github - не кажется подчиняться

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

Я создал свой собственный настраиваемый атрибут и фильтр, чтобы попытаться установить свойство как допускающее значение NULL

[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, что может быть несколько раз в день в циклах разработки.

У меня есть обходной путь - я перехватываю ответ json и добавляю "nullable" = true на свой сервер там, где это необходимо, используя соответствие регулярного выражения в строке json ответа ответа перед обслуживая его клиентом. Это действительно взломано, и я бы хотел, чтобы это было сделано, если он существует.

Любая помощь приветствуется!

1 Ответ

0 голосов
/ 17 июня 2020

Существует параметр, который выполняет это:

UseAllOfToExtendReferenceSchemas 

Он изменяет схему на this, которую 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();
            ...
...