Поделиться через


Обработка ошибок в api ASP.NET Core

Замечание

Это не последняя версия этой статьи. В текущей версии см. версию .NET 10 этой статьи.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Для получения дополнительной информации см. Политику поддержки .NET и .NET Core. Для текущей версии см. версию .NET 9 этой статьи.

В этой статье описывается обработка ошибок в ASP.NET основных API. Выбрана документация по минимальным API. Чтобы просмотреть документацию по API на основе контроллеров, перейдите на вкладку "Контроллеры". Инструкции Blazor по обработке ошибок см. в разделе "Обработка ошибок" в приложениях ASP.NET CoreBlazor.

Страница исключений разработчика

На странице исключений разработчика отображаются подробные сведения об необработанных исключениях запросов. Он используется DeveloperExceptionPageMiddleware для записи синхронных и асинхронных исключений из конвейера HTTP и создания ответов об ошибках. Страница исключений разработчика выполняется в начале конвейера ПО промежуточного слоя, чтобы он смог перехватывать необработанные исключения, создаваемые в по промежуточном слоям, следующим образом.

ASP.NET Приложения Core по умолчанию позволяют включить страницу исключений разработчика, если оба:

Приложения, созданные с помощью WebHost.CreateDefaultBuilderпредыдущих шаблонов, могут включить страницу исключения разработчика, вызвав вызов app.UseDeveloperExceptionPage.

Предупреждение

Не включите страницу исключений разработчика, если приложение не запущено в среде разработки. Не делитесь подробными сведениями об исключениях публично при запуске приложения в рабочей среде. Дополнительные сведения о настройке сред см. в ASP.NET средах выполнения Core.

Страница исключений разработчика может содержать следующие сведения об исключении и запросе:

  • Трассировка стека
  • Параметры строки запроса, если таковые есть
  • Файлы cookie, если таковые есть
  • Headers
  • Метаданные конечной точки, если таковые есть

Страница исключений разработчика не гарантирует предоставления каких-либо сведений. Используйте ведение журнала для полных сведений об ошибке.

На следующем рисунке показана пример страницы исключений разработчика с анимацией для отображения вкладок и отображаемых сведений:

Страница исключений разработчика, анимированная для отображения каждой выбранной вкладки.

В ответ на запрос с заголовком страница исключений разработчика возвращает обычный Accept: text/plain текст вместо HTML. Рассмотрим пример.

Status: 500 Internal Server Error
Time: 9.39 msSize: 480 bytes
FormattedRawHeadersRequest
Body
text/plain; charset=utf-8, 480 bytes
System.InvalidOperationException: Sample Exception
   at WebApplicationMinimal.Program.<>c.<Main>b__0_0() in C:\Source\WebApplicationMinimal\Program.cs:line 12
   at lambda_method1(Closure, Object, HttpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

HEADERS
=======
Accept: text/plain
Host: localhost:7267
traceparent: 00-0eab195ea19d07b90a46cd7d6bf2f

Чтобы просмотреть страницу исключений разработчика в минимальном API:

В этом разделе приведен пример приложения, демонстрирующий способы обработки исключений в минимальном API. Он создает исключение при запросе конечной точки /exception :

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Обработчик исключений

В средах, отличных от разработки, используйте ПО промежуточного слоя обработчика исключений для создания полезных данных об ошибке.

Чтобы настроить Exception Handler Middleware, вызовите UseExceptionHandler. Например, следующий код изменяет приложение для реагирования на полезные данные, совместимые с RFC 7807, на клиент. Дополнительные сведения см. в разделе "Сведения о проблеме" далее в этой статье.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp 
    => exceptionHandlerApp.Run(async context 
        => await Results.Problem()
                     .ExecuteAsync(context)));

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Ответы на ошибки клиента и сервера

Рассмотрим следующее минимальное приложение API.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

/users Конечная точка создает 200 OK представление json о том, User когда id больше 0, в противном случае 400 BAD REQUEST код состояния без текста ответа. Дополнительные сведения о создании ответа см. в статье "Создание ответов" в приложениях API "Минимальный".

Его Status Code Pages middleware можно настроить для создания общего содержимого текста, если пусто для всех ответов HTTP-клиента (400-499) или сервера.500 -599 ПО промежуточного слоя настраивается путем вызова метода расширения UseStatusCodePages .

Например, в следующем примере приложение изменяет ответ на полезные данные, совместимые с RFC 7807, для всех ответов клиента и сервера, включая ошибки маршрутизации (например, 404 NOT FOUND). Дополнительные сведения см. в разделе "Сведения о проблеме ".

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseStatusCodePages(async statusCodeContext 
    => await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
                 .ExecuteAsync(statusCodeContext.HttpContext));

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Сведения о проблеме

Сведения о проблеме — это не единственный формат ответа, описывающий ошибку API HTTP, однако они часто используются для сообщения об ошибках для API HTTP.

Служба сведений о проблеме IProblemDetailsService реализует интерфейс, который поддерживает создание сведений о проблеме в ASP.NET Core. Метод AddProblemDetails(IServiceCollection) расширения для IServiceCollection регистрации реализации по умолчанию IProblemDetailsService .

В приложениях ASP.NET Core по промежуточному слоям по промежуточному слоя возникает проблема, когда вызывается ответы AddProblemDetails HTTP, за исключением случаев, когда Accept заголовок HTTP запроса не включает один из типов контента, поддерживаемых зарегистрированным IProblemDetailsWriter (по умолчанию: application/json):

  • ExceptionHandlerMiddleware: создает ответ сведений о проблеме, когда настраиваемый обработчик не определен.
  • StatusCodePagesMiddleware: создает ответ сведений о проблеме по умолчанию.
  • DeveloperExceptionPageMiddleware: создает ответ сведений о проблеме в разработке, если Accept заголовок HTTP запроса не включает text/html.

Минимальные приложения API можно настроить для создания ответа сведений о проблеме для всех ответов об ошибках HTTP-клиента и сервера, которые еще не содержат содержимогоAddProblemDetails текста с помощью метода расширения.

Следующий код настраивает приложение для создания сведений о проблеме:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Дополнительные сведения об использовании AddProblemDetailsсм. в разделе "Сведения о проблеме"

Резервная часть IProblemDetailsService

В следующем коде возвращает ошибку, httpContext.Response.WriteAsync("Fallback: An error occurred.") если IProblemDetailsService реализация не может создать ProblemDetails:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/exception", () =>
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Предыдущий код:

Следующий пример аналогичен предыдущему, за исключением того, что вызывается .Status Code Pages middleware

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseStatusCodePages(statusCodeHandlerApp =>
{
    statusCodeHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/users/{id:int}", (int id) =>
{
    return id <= 0 ? Results.BadRequest() : Results.Ok(new User(id));
});

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Дополнительные функции обработки ошибок

Миграция с контроллеров на минимальные API

Если вы переносите API на основе контроллера на минимальные API:

  1. Замена фильтров действий фильтрами конечных точек или ПО промежуточного слоя
  2. Замена проверки модели ручной проверкой или пользовательской привязкой
  3. Замена фильтров исключений по промежуточному слоям обработки исключений
  4. Настройка сведений о проблеме с использованием AddProblemDetails() для согласованных ответов об ошибках

Когда следует использовать обработку ошибок на основе контроллера

При необходимости рассмотрите api на основе контроллера:

  • Сложные сценарии проверки моделей
  • Централизованная обработка исключений между несколькими контроллерами
  • Точное управление форматированием ответа на ошибки
  • Интеграция с функциями MVC, такими как фильтры и соглашения

Подробные сведения об обработке ошибок на основе контроллера, включая ошибки проверки, настройку сведений о проблеме и фильтры исключений, см. в разделах вкладки "Контроллеры ".

Дополнительные ресурсы