Обработка ошибок в минимальных приложениях API

Примечание.

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

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске см . версию .NET 8 этой статьи.

С вкладом ДэвидА Акера

В этой статье описывается обработка ошибок в минимальных приложениях API.

Исключения

В приложении 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();

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

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

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

Дополнительные сведения о настройке ПО промежуточного слоя см. в разделе "По промежуточного слоя" в минимальных приложениях API.

Developer Exception Page При обнаружении необработанного исключения при обнаружении необработанного исключения создается ответ обычного текста по умолчанию, аналогичный следующему примеру:

HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
Date: Thu, 27 Oct 2022 18:00:59 GMT
Server: Kestrel
Transfer-Encoding: chunked

    System.InvalidOperationException: Sample Exception
    at Program.<>c.<<Main>$>b__0_1() in ....:line 17
    at lambda_method2(Closure, Object, HttpContext)
    at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
    --- End of stack trace from previous location ---
    at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Connection: keep-alive
Host: localhost:5239
Accept-Encoding: gzip, deflate, br

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

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

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

В средах, отличных от разработки, используйте ПО промежуточного слоя обработчика исключений для создания полезных данных об ошибке. Чтобы настроить 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-клиента (499-400) или сервера.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 регистрации реализации по умолчанию IProblemDetailsService .

В приложениях ASP.NET Core следующий по промежуточному слоя создает ответы HTTP для получения сведений о проблемах при AddProblemDetails вызове, за исключением случаев, когда 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();

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

  • Записывает сообщение об ошибке с резервным кодом, если не problemDetailsService удается написать сообщение об ошибке ProblemDetails. Например, конечная точка, в которой заголовок запроса Accept указывает тип носителя, который DefaulProblemDetailsWriter не поддерживается.
  • Использует ПО промежуточного слоя обработчика исключений.

Следующий пример аналогичен предыдущему, за исключением того, что вызывается .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 с минимальным количеством способов обработки исключений. Он создает исключение при запросе конечной точки /exception :

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

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

app.Run();

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

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

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

Дополнительные сведения о настройке ПО промежуточного слоя см. в разделе "По промежуточного слоя" в минимальных приложениях API.

Developer Exception Page При обнаружении необработанного исключения при обнаружении необработанного исключения создается ответ обычного текста по умолчанию, аналогичный следующему примеру:

HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
Date: Thu, 27 Oct 2022 18:00:59 GMT
Server: Kestrel
Transfer-Encoding: chunked

    System.InvalidOperationException: Sample Exception
    at Program.<>c.<<Main>$>b__0_1() in ....:line 17
    at lambda_method2(Closure, Object, HttpContext)
    at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
    --- End of stack trace from previous location ---
    at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Connection: keep-alive
Host: localhost:5239
Accept-Encoding: gzip, deflate, br

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

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

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

В средах, отличных от разработки, используйте ПО промежуточного слоя обработчика исключений для создания полезных данных об ошибке. Чтобы настроить 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.Map("/exception", () 
    => { throw new InvalidOperationException("Sample Exception"); });

app.Run();

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

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

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

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

app.Run();

public record User(int Id);

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

Его Status Code Pages middleware можно настроить для создания общего содержимого текста, если пусто для всех ответов HTTP-клиента (499-400) или сервера.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.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.Run();

public record User(int Id);

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

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

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

В приложениях ASP.NET Core следующий по промежуточному слоя создает ответы HTTP для получения сведений о проблемах при AddProblemDetails вызове, за исключением случаев, когда 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.Map("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

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

app.Run();

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