Я создаю сервер 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, чтобы клиент мог обрабатывать результаты с нулевым значением?





Сделайте следующее, это вам поможет:
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"
}
Кажется, это не работает. Или, по крайней мере, изменение результата метода на ActionResult<DateTime?> создает схему JSON без ответа 404, как вы указали. Я могу добиться этого результата, добавив [ProducesResponseType(StatusCodes.Status404NotFound)] к методу контроллера, но тогда сгенерированный код не сможет скомпилироваться, поскольку он не знает, что такое ProblemDetails (плюс он все равно генерирует результат, не допускающий значения NULL). Это явно не правильный путь.
Кажется, в Swashbuckle.AspNetCore это сейчас не работает, так как генерируются неверные схемы: github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2793
@MBender Я считаю, что возврат 404 Not Found более подходит для запросов GET, когда ресурс не найден. Этот код состояния явно сообщает, что ресурс не существует, что важно для того, чтобы клиенты понимали природу отсутствия данных. Использование 204 No Content обычно подходит для сценариев, где ресурс существует, но нет содержимого для возврата, что не соответствует намерению указать несуществующий ресурс. Что касается проблемы создания схемы и сведений о проблеме, добавление [ProducesResponseType к методу контроллера является правильным подходом.
Нет, это не так. Даже возврат 404 не допускает обнуления, как я ожидал. Как уже говорилось, это ошибка в текущей реализации Swashbuckle.
Кстати, 204 против 404 (по-видимому) являются обычным спором, как и тема о том, как обрабатывать коды ответа 2xx. Однако, если контроллер явно определен как способный возвращать DateTime? (или что-нибудь Nullable<>), то null НЕ является ошибкой по этому самому определению, и поэтому 404 не применяется.
Когда null представляет концепцию «не удалось найти то, что вы просили», тогда значение null должно быть 404, и именно об этом явно говорится в вашем комментарии «если ключ не существует, это может быть значение null». Если ваш API используется только в вашей собственной экосистеме, споры бессмысленны. Но если вы раскрываете это внешним системам, помните, что не все системы используют .NET. Если то, что они запрашивали, не было найдено, null, возвращаемый вашим методом, говорит вам «не найдено», поэтому возврат 404 в этом случае — это то, чего ожидает клиент.
Это отличается от запроса /widgets/10486/discontinued-date для виджета, выпуск которого еще не прекращен, и в этом случае null должен быть представлен как 204 No Content. Запись виджета существует, но у нее нет значения для этого поля.
Причина дебатов во многом связана с людьми, которые смешивают различные концепции или пытаются заставить все работать с концепциями .NET, не принимая во внимание структуру протокола HTTP. Если вы сосредоточитесь на семантике, большая часть дискуссий исчезнет.
«если ключ не существует, он может быть нулевым» — это внутренняя часть. API, определяя результат как DateTime?, допускает значения NULL, то есть клиент сам решает, что делать с значением NULL. В любом случае этот ответ совершенно неверен, поскольку он не решает реальную проблему, а именно то, что Swashbuckle.AspNetCore в настоящее время дает сбой с нулями в различных местах, и предлагает вводящее в заблуждение предложение о том, как исправить эту или подобные проблемы.
Оказывается, 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>();
})
Так фокус в том, чтобы вернуться
NotFound? Мне кажется, что такой ответ указывает на ошибку, где, возможно, лучше подойдет 204 (т. е. ОК, но нет контента).