Обнуляемые ответы в ApiController

Я создаю сервер ASP.Net Core (с соответствующим клиентом .Net Core) и использую некоторые методы для возврата значений null. К сожалению, схема Swagger, похоже, не отражает этого, а в методах отсутствует атрибут "nullable": true.

Пример метода API:

[ApiController]
public class DataController : ControllerBase
{
  public DateTime? GetSomeDateValue(string key)
  {
     DateTime? result = GrabTheResultFromTheDatabase(key); //<- if the key doesn't exist, this can be null and this is expected
     return result;
  }
}

Для справки: я создаю клиента, используя следующее .csproj определение:

<OpenApiReference Include = "..\Backend\BackendService.json" CodeGenerator = "NSwagCSharp" Link = "OpenAPIs\BackendService.json">
   <Options>/GenerateClientInterfaces:true /AdditionalNamespaceUsages:Base.Entities /GenerateDtoTypes:false</Options>
</OpenApiReference>

Как мне настроить контроллер/NSwagCSharp, чтобы клиент мог обрабатывать результаты с нулевым значением?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
108
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Сделайте следующее, это вам поможет:

1- вернуть ActionResult или IActionResult для лучшего результата. потому что API должен возвращать статус. означает: ActionResult<DateTime?> вместо просто DateTime? Это обеспечивает большую гибкость при обработке различных сценариев ответа, таких как возврат ошибки 404 Not Found, если ключ не существует.

Код:

[HttpGet("GetSomeDateValue")]
public ActionResult<DateTime?> GetSomeDateValue(string key)
{
    DateTime? result = GrabTheResultFromTheDatabase(key);
    if (result == null)
    {
        return NotFound(); // Return a 404 Not Found if the key doesn't exist
    }
    return Ok(result);
}

2- Также проверьте конфигурации NSwag на наличие типов, допускающих значение NULL. он должен отражать обнуляемую природу ответа.

GenerateNullableReferenceTypes должно иметь значение true.

<OpenApiReference Include = "..\Backend\BackendService.json" CodeGenerator = "NSwagCSharp" Link = "OpenAPIs\BackendService.json">
   <Options>/GenerateClientInterfaces:true /AdditionalNamespaceUsages:Base.Entities /GenerateDtoTypes:false /GenerateNullableReferenceTypes:true</Options>
</OpenApiReference>

Также проверьте конфигурацию json. должно быть что-то вроде этого.

 "responses": {
        "200": {
          "description": "Success",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "result": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "404": {
          "description": "Not Found"
        }

Так фокус в том, чтобы вернуться NotFound? Мне кажется, что такой ответ указывает на ошибку, где, возможно, лучше подойдет 204 (т. е. ОК, но нет контента).

MBender 16.06.2024 17:02

Кажется, это не работает. Или, по крайней мере, изменение результата метода на ActionResult<DateTime?> создает схему JSON без ответа 404, как вы указали. Я могу добиться этого результата, добавив [ProducesResponseType(StatusCodes.Status404NotFound)] к методу контроллера, но тогда сгенерированный код не сможет скомпилироваться, поскольку он не знает, что такое ProblemDetails (плюс он все равно генерирует результат, не допускающий значения NULL). Это явно не правильный путь.

MBender 16.06.2024 17:41

Кажется, в Swashbuckle.AspNetCore это сейчас не работает, так как генерируются неверные схемы: github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/279‌​3

MBender 16.06.2024 18:15

@MBender Я считаю, что возврат 404 Not Found более подходит для запросов GET, когда ресурс не найден. Этот код состояния явно сообщает, что ресурс не существует, что важно для того, чтобы клиенты понимали природу отсутствия данных. Использование 204 No Content обычно подходит для сценариев, где ресурс существует, но нет содержимого для возврата, что не соответствует намерению указать несуществующий ресурс. Что касается проблемы создания схемы и сведений о проблеме, добавление [ProducesResponseType к методу контроллера является правильным подходом.

Ali Hemmati 16.06.2024 19:01

Нет, это не так. Даже возврат 404 не допускает обнуления, как я ожидал. Как уже говорилось, это ошибка в текущей реализации Swashbuckle.

MBender 16.06.2024 19:10

Кстати, 204 против 404 (по-видимому) являются обычным спором, как и тема о том, как обрабатывать коды ответа 2xx. Однако, если контроллер явно определен как способный возвращать DateTime? (или что-нибудь Nullable<>), то null НЕ является ошибкой по этому самому определению, и поэтому 404 не применяется.

MBender 16.06.2024 21:07

Когда null представляет концепцию «не удалось найти то, что вы просили», тогда значение null должно быть 404, и именно об этом явно говорится в вашем комментарии «если ключ не существует, это может быть значение null». Если ваш API используется только в вашей собственной экосистеме, споры бессмысленны. Но если вы раскрываете это внешним системам, помните, что не все системы используют .NET. Если то, что они запрашивали, не было найдено, null, возвращаемый вашим методом, говорит вам «не найдено», поэтому возврат 404 в этом случае — это то, чего ожидает клиент.

madreflection 16.06.2024 21:32

Это отличается от запроса /widgets/10486/discontinued-date для виджета, выпуск которого еще не прекращен, и в этом случае null должен быть представлен как 204 No Content. Запись виджета существует, но у нее нет значения для этого поля.

madreflection 16.06.2024 21:32

Причина дебатов во многом связана с людьми, которые смешивают различные концепции или пытаются заставить все работать с концепциями .NET, не принимая во внимание структуру протокола HTTP. Если вы сосредоточитесь на семантике, большая часть дискуссий исчезнет.

madreflection 16.06.2024 21:36

«если ключ не существует, он может быть нулевым» — это внутренняя часть. API, определяя результат как DateTime?, допускает значения NULL, то есть клиент сам решает, что делать с значением NULL. В любом случае этот ответ совершенно неверен, поскольку он не решает реальную проблему, а именно то, что Swashbuckle.AspNetCore в настоящее время дает сбой с нулями в различных местах, и предлагает вводящее в заблуждение предложение о том, как исправить эту или подобные проблемы.

MBender 17.06.2024 23:06
Ответ принят как подходящий

Оказывается, Swashbuckle.AspNetCoreв настоящее время есть проблемы с ​​примитивами, допускающими значение NULL.

Использование DotSwashbuckle.AspNetCore оказалось лучшим подходом (по крайней мере, до тех пор, пока проблемы с обнулением не будут исправлены в Swashbuckle.AspNetCore).

Кроме того, мне пришлось пометить мой метод контроллера как способный возвращать типы, допускающие значение NULL, для кода состояния 204 (так называемого «нет содержимого»), иначе сгенерированный код на стороне клиента будет рассматривать 204 как исключение.

[HttpGet("[action]")]
[ProducesResponseType<DateTime?>(StatusCodes.Status200OK)]
[ProducesResponseType<DateTime?>(StatusCodes.Status204NoContent)]
public DateTime? GetSomeDateValue(string key) => MyMagicMethodThatReturnsValue(key);

Также можно отключить использование ASP.NET Core 204, что означает, что атрибуты ProducesResponseType больше не требуются.

services.AddControllers(opt =>  // or AddMvc()
{
    // remove formatter that turns nulls into 204 - No Content responses
    opt.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
})

Другие вопросы по теме