ControllerBase содержит такие методы, как Conflict(), которые возвращают объект ConflictResult (представляющий ответ HTTP 409), производный от StatusCodeResult. Результирующее тело ответа имеет тип содержимого application/problem+json и выглядит следующим образом:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.8",
"title": "Conflict",
"status": 409,
"traceId": "0HLO99QHFC9QI:00000001"
}
Для ответа HTTP 410 нет встроенного метода/класса, поэтому я сделал его:
[DefaultStatusCode(410)]
public class GoneResult : StatusCodeResult
{
public GoneResult() : base(410)
{}
}
...
public static class ControllerBaseExtensions
{
public static GoneResult Gone(this ControllerBase controllerBase) // this doesn't give all the problem+JSON attributes
{
return new GoneResult();
}
}
Однако это дает
{
"type": "about:blank",
"status": 410
}
то есть значение type отличается, а поля title и traceId отсутствуют.
Я также хотел бы создать собственный класс для ответа HTTP 500, который включает поле message с сообщением об ошибке. Я пытался вернуть StatusCode(StatusCodes.Status500InternalServerError), что дает мне тот же минимальный ответ application/problem+json, что и мой метод Gone(); Я также пытался вернуть StatusCode(StatusCodes.Status500InternalServerError, message), что дает мне сообщение об ошибке, но форматирует ответ как text/plain.





Просто вы должны вернуть тело ответа ProblemDetails. Мне пришлось бы копаться в коде, чтобы быть уверенным, но я думаю, что ASP.NET Core делает это через промежуточное ПО только для определенных результатов. Они сказать что-либо в диапазоне 4xx, но я думаю, что на самом деле это просто ограничено встроенными типами результатов, которые возвращают коды состояния в этом диапазоне, а не результатом Любые с кодом состояния 4xx. Опять же, это предположение, поскольку я не смотрел, что именно они делают, хотя это не происходит как часть фактического результирующего класса.
Для ваших целей есть несколько способов справиться с этим. Вы можете написать собственное промежуточное ПО, чтобы перехватывать исходящие ответы и переписывать их. Вы можете использовать собственный обработчик исключений. Вместо этого вы можете просто наследоваться от ObjectResult, а затем просто создать экземпляр ProblemDetails самостоятельно и поместить его в базу. Вы даже можете просто вернуть ProblemDetails прямо из своего действия (хотя это, очевидно, наименее оптимальный способ).
Большое спасибо, Крис. Для 500 ошибок я реализовал собственный обработчик исключений и использовал пакет nuget.org/packages/Hellang.Middleware.ProblemDetails для тяжелой работы — теперь он работает хорошо.
Код, генерирующий ответ ProblemDetails, не знает о коде состояния 410, поэтому у него нет связанных свойств Link и Title, которые можно использовать при построении объекта ответа. Чтобы добавить эту осведомленность, настройте ApiBehaviorOptions в ConfigureServices следующим образом:
services.Configure<ApiBehaviorOptions>(options =>
{
options.ClientErrorMapping[410] = new ClientErrorData
{
Title = "Gone",
Link = "https://tools.ietf.org/html/rfc7231#section-6.5.9"
};
});
ClientErrorMapping — это словарь от int (код состояния) до ClientErrorData. Обратите внимание, что значение, которое я использовал для Link выше, действительно указывает на правильный раздел RFC.
Хороший. Я подумал, что есть какой-то способ сделать это, но ничего не нашел в документах или исходниках. Хотя, конечно, я не тратил кучу времени на поиски. Из любопытства, у вас есть источник для дальнейшего использования?
@ChrisPratt В документах есть это, а в исходном коде 2.2 есть это. Есть также фабрика.
Спасибо. Я вчера буквально просматривал страницу из документов и все равно как-то пропустил ее. Шиш.
Два вопроса, которые вы задали здесь, имеют разные решения (imo). Я добавил ответ, касающийся вопроса 410, но другой ответ, который у вас есть (на момент написания этой статьи), касается вопроса 500. Я не вижу особого смысла в решении второго вопроса в ответе, который я дал, так как он обычно просто повторяет вторую половину другого ответа (я бы предпочел не возвращать явные 500, а использовать исключения и встроенный материал обработчика исключений, но это только мое мнение).