다음을 통해 공유


최소 API 앱에서 오류를 처리하는 방법

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Warning

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조 하세요. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

데이비드 애커의 기여와 함께

이 문서에서는 최소 API 앱에서 오류를 처리하는 방법을 설명합니다. 컨트롤러 기반 API 의 오류 처리에 대한 자세한 내용은 ASP.NET Core 의 오류 처리 및 ASP.NET Core 컨트롤러 기반 웹 API의 오류 처리를 참조하세요.

예외

최소 API 앱에는 처리되지 않은 예외를 처리하는 두 가지 기본 제공 중앙 집중식 메커니즘이 있습니다.

이 섹션에서는 최소 API에서 예외를 처리하는 방법을 보여 주는 다음 샘플 앱을 참조합니다. 엔드포인트 /exception가 요청되면 예외를 throw합니다.

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 파이프라인에서 동기 및 비동기 예외를 캡처하고 오류 응답을 생성합니다. 개발자 예외 페이지는 미들웨어 파이프라인의 앞부분에 실행되므로, 다음에 오는 미들웨어에서 throw된 미처리 예외를 catch할 수 있습니다.

ASP.NET Core 앱은 다음과 같은 경우 기본적으로 개발자 예외 페이지를 사용할 수 있습니다.

이전 템플릿을 사용하여 만든 앱, 즉, 사용하여 WebHost.CreateDefaultBuilder개발자 예외 페이지를 호출 app.UseDeveloperExceptionPage하여 사용하도록 설정할 수 있습니다.

Warning

앱이 개발 환경에서 실행 중인 경우에만 개발자 예외 페이지를 사용하도록 설정하지 마세요. 프로덕션 환경에서 앱을 실행할 때 자세한 예외 정보를 공개적으로 공유하지 마세요. 환경을 구성하는 방법에 대한 자세한 내용은 ASP.NET Core에서 여러 환경 사용을 참조하세요.

개발자 예외 페이지에는 예외 및 요청에 대한 다음 정보가 포함될 수 있습니다.

  • 스택 추적
  • 쿼리 문자열 매개 변수(있는 경우)
  • 쿠키(있는 경우)
  • 헤더
  • 엔드포인트 메타데이터(있는 경우)

개발자 예외 페이지는 어떠한 정보 제공도 보장하지 않습니다. 전체 오류 정보를 보려면 로깅을 사용하세요.

다음 이미지는 탭 및 표시되는 정보를 표시하는 애니메이션이 있는 샘플 개발자 예외 페이지를 보여 줍니다.

선택한 각 탭을 표시하기 위해 애니메이션 효과를 준 개발자 예외 페이지입니다.

헤더가 있는 요청에 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

개발자 예외 페이지를 보려면:

  • 개발 환경에서 샘플 앱을 실행합니다.
  • 엔드포인트로 /exception 이동합니다.

예외 처리기

비개발 환경에서는 예외 처리 미들웨어를 사용하여 오류 페이로드를 생성할 수 있습니다. 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 엔드포인트는 id0보다 크면 User를 나타내는 json과 함께 200 OK를 생성하고, 그렇지 않으면 응답 본문이 없는 400 BAD REQUEST 상태 코드를 생성합니다. 응답을 만드는 방법에 대한 자세한 내용은 최소 API 앱에서 응답 만들기를 참조하세요.

Status Code Pages middleware는 모든 HTTP 클라이언트(400-499) 또는 서버(500 -599) 응답에 대해 비어 있는 경우, 공용 본문 콘텐츠를 생성하도록 구성할 수 있습니다. 미들웨어는 UseStatusCodePages 확장 메서드를 호출하여 구성됩니다.

예를 들어, 다음 예제에서는 라우팅 오류(예: 404 NOT FOUND)를 포함하여 모든 클라이언트 및 서버 응답에 대해 RFC 7807 규격 페이로드로 응답하도록 앱을 클라이언트로 변경합니다. 자세한 내용은 문제 세부 정보 섹션을 참조하세요.

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);

문제 세부 정보

문제 세부 정보는 HTTP API 오류를 설명하는 유일한 응답 형식은 아니지만 일반적으로 HTTP API에 대한 오류를 보고하는 데 사용됩니다.

문제 세부 정보 서비스는 ASP.NET Core 문제 세부 정보 만들기를 지원하는 IProblemDetailsService 인터페이스를 구현합니다. IServiceCollectionAddProblemDetails(IServiceCollection) 확장 메서드는 기본 IProblemDetailsService 구현을 등록합니다.

ASP.NET Core 앱에서 다음 미들웨어는 Accept이 등록된 IProblemDetailsWriter(기본값: application/json)가 지원되는 콘텐츠 형식 중 하나가 포함되지 않은 HTTP 헤더를 요청하는 경우를 제외하고 AddProblemDetails가 호출될 때 문제 세부 정보 HTTP 응답을 생성합니다.

확장 메서드를 사용하여 AddProblemDetails 아직 본문 콘텐츠가 없는 모든 HTTP 클라이언트 및 서버 오류 응답에 대한 문제 세부 정보 응답을 생성하도록 최소 API 앱을 구성할 수 있습니다.

다음 코드는 문제 세부 정보를 생성하도록 앱을 구성합니다.

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가 요청되면 예외를 throw합니다.

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 앱의 미들웨어를 참조하세요.

위의 최소 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

Warning

앱이 개발 환경에서 실행 중인 경우에만 개발자 예외 페이지를 사용하도록 설정하지 마세요. 프로덕션 환경에서 앱을 실행할 때 자세한 예외 정보를 공개적으로 공유하지 마세요. 환경을 구성하는 방법에 대한 자세한 내용은 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 엔드포인트는 id0보다 크면 User를 나타내는 json과 함께 200 OK를 생성하고, 그렇지 않으면 응답 본문이 없는 400 BAD REQUEST 상태 코드를 생성합니다. 응답을 만드는 방법에 대한 자세한 내용은 최소 API 앱에서 응답 만들기를 참조하세요.

Status Code Pages middleware는 모든 HTTP 클라이언트(400-499) 또는 서버(500 -599) 응답에 대해 비어 있는 경우, 공용 본문 콘텐츠를 생성하도록 구성할 수 있습니다. 미들웨어는 UseStatusCodePages 확장 메서드를 호출하여 구성됩니다.

예를 들어, 다음 예제에서는 라우팅 오류(예: 404 NOT FOUND)를 포함하여 모든 클라이언트 및 서버 응답에 대해 RFC 7807 규격 페이로드로 응답하도록 앱을 클라이언트로 변경합니다. 자세한 내용은 문제 세부 정보 섹션을 참조하세요.

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);

문제 세부 정보

문제 세부 정보는 HTTP API 오류를 설명하는 유일한 응답 형식은 아니지만 일반적으로 HTTP API에 대한 오류를 보고하는 데 사용됩니다.

문제 세부 정보 서비스는 ASP.NET Core 문제 세부 정보 만들기를 지원하는 IProblemDetailsService 인터페이스를 구현합니다. IServiceCollectionAddProblemDetails(IServiceCollection) 확장 메서드는 기본 IProblemDetailsService 구현을 등록합니다.

ASP.NET Core 앱에서 다음 미들웨어는 Accept이 등록된 IProblemDetailsWriter(기본값: application/json)가 지원되는 콘텐츠 형식 중 하나가 포함되지 않은 HTTP 헤더를 요청하는 경우를 제외하고 AddProblemDetails가 호출될 때 문제 세부 정보 HTTP 응답을 생성합니다.

최소 API 앱은 AddProblemDetails 확장 메서드를 사용하여 아직 본문 콘텐츠가 없는 모든 HTTP 클라이언트 및 서버 오류 응답에 대한 문제 세부 정보 응답을 생성하도록 구성할 수 있습니다.

다음 코드는 문제 세부 정보를 생성하도록 앱을 구성합니다.

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 사용에 대한 자세한 내용은 문제 세부 정보를 참조하세요.