Microsoft .NET/ASP.Net & ASP.Net Core

[ASP.NET Core] 전역 예외 처리, IExceptionHandler와 ProblemDetails (.NET 8)

전자기린 2026. 11. 10. 00:47

.NET 8에서 추가된 IExceptionHandler로 예외 응답을 한 곳에서 처리하는 방법입니다. 컨트롤러마다 try-catch를 넣지 않아도 됩니다.

절차

  1. 핸들러 작성
  2. 등록
  3. 응답 형식 확인
  4. 주의할 점

 

1. 핸들러 작성

public class GlobalExceptionHandler : IExceptionHandler
{
    private readonly ILogger<GlobalExceptionHandler> _logger;
    public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger) => _logger = logger;

    public async ValueTask<bool> TryHandleAsync(HttpContext ctx, Exception ex, CancellationToken ct)
    {
        _logger.LogError(ex, "처리되지 않은 예외: {Path}", ctx.Request.Path);

        var (status, title) = ex switch
        {
            KeyNotFoundException => (StatusCodes.Status404NotFound, "리소스를 찾을 수 없습니다."),
            UnauthorizedAccessException => (StatusCodes.Status403Forbidden, "권한이 없습니다."),
            _ => (StatusCodes.Status500InternalServerError, "서버 오류가 발생했습니다.")
        };

        ctx.Response.StatusCode = status;
        await ctx.Response.WriteAsJsonAsync(new { title, traceId = ctx.TraceIdentifier }, ct);
        return true;   // 처리했으면 true
    }
}

2. 등록

builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
builder.Services.AddProblemDetails();

var app = builder.Build();
app.UseExceptionHandler();   // 파이프라인 앞쪽에

3. 응답 확인

예외가 나면 아래 형태로 내려갑니다.

{
  "title": "서버 오류가 발생했습니다.",
  "traceId": "0HN7ABCDEF"
}

traceId를 로그와 함께 남기면 사용자 문의 때 바로 찾을 수 있습니다.

4. 주의할 점

  1. UseExceptionHandler()는 UseRouting() 뒤, 엔드포인트 실행 전에 둡니다
  2. 개발 환경에서는 UseDeveloperExceptionPage()가 먼저 걸려 스택이 보입니다
  3. 응답을 이미 쓰기 시작한 뒤에는 바꿀 수 없습니다 — 파일 다운로드 중 예외 등

정리

  1. 핸들러는 예외 타입별로 상태 코드를 매핑
  2. 등록은 AddExceptionHandler + UseExceptionHandler
  3. traceId로 로그와 응답을 연결