[c#] ASP.NET Web Api에서 처리되지 않은 모든 예외 포착

ASP.NET Web Api에서 발생하는 처리되지 않은 모든 예외를 어떻게 포착 하여 기록 할 수 있습니까?

지금까지 시도했습니다.

  • 생성 및 등록 ExceptionHandlingAttribute
  • Application_Error메서드 구현Global.asax.cs
  • 구독 AppDomain.CurrentDomain.UnhandledException
  • 구독 TaskScheduler.UnobservedTaskException

ExceptionHandlingAttribute컨트롤러 작업 메서드 및 작업 필터 내에서 throw 된 예외를 성공적으로 처리하지만 다른 예외는 처리되지 않습니다. 예를 들면 다음과 같습니다.

  • IQueryable작업 메서드 에서 반환 된 실행에 실패 할 때 throw되는 예외
  • 메시지 처리기에 의해 throw 예외 (예 HttpConfiguration.MessageHandlers)
  • 컨트롤러 인스턴스를 만들 때 throw되는 예외

기본적으로 예외로 인해 500 내부 서버 오류가 클라이언트에 반환되는 경우 로깅을 원합니다. Application_ErrorWeb Forms 및 MVC에서이 작업을 잘 구현 했습니다. Web Api에서 무엇을 사용할 수 있습니까?



답변

이제 WebAPI 2.1에서 가능합니다 ( 새로운 기능 참조 ).

IExceptionLogger 구현을 하나 이상 만듭니다. 예를 들면 :

public class TraceExceptionLogger : ExceptionLogger
{
    public override void Log(ExceptionLoggerContext context)
    {
        Trace.TraceError(context.ExceptionContext.Exception.ToString());
    }
}

그런 다음 다음과 같이 구성 콜백 내에서 애플리케이션의 HttpConfiguration에 등록합니다.

config.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());

또는 직접 :

GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());


답변

Yuval의 대답은 링크 된 페이지 에 명시된대로 로깅이 아닌 Web API에서 포착 된 처리되지 않은 예외에 대한 응답을 사용자 지정하는 것 입니다. 자세한 내용은 페이지의 사용시기 섹션을 참조하십시오. 로거는 항상 호출되지만 핸들러는 응답을 보낼 수있는 경우에만 호출됩니다. 간단히 말해서 로거 를 사용하여 로그하고 핸들러를 사용하여 응답을 사용자 정의하십시오.

그건 그렇고, 나는 어셈블리 v5.2.3을 사용하고 있으며 ExceptionHandler클래스에는 HandleCore메서드 가 없습니다 . 이에 상응하는 것은 Handle. 그러나 단순히 하위 클래스 지정 ExceptionHandler(Yuval의 답변에서와 같이)은 작동하지 않습니다. 제 경우에는 IExceptionHandler다음과 같이 구현 해야합니다.

internal class OopsExceptionHandler : IExceptionHandler
{
    private readonly IExceptionHandler _innerHandler;

    public OopsExceptionHandler (IExceptionHandler innerHandler)
    {
        if (innerHandler == null)
            throw new ArgumentNullException(nameof(innerHandler));

        _innerHandler = innerHandler;
    }

    public IExceptionHandler InnerHandler
    {
        get { return _innerHandler; }
    }

    public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
    {
        Handle(context);

        return Task.FromResult<object>(null);
    }

    public void Handle(ExceptionHandlerContext context)
    {
        // Create your own custom result here...
        // In dev, you might want to null out the result
        // to display the YSOD.
        // context.Result = null;
        context.Result = new InternalServerErrorResult(context.Request);
    }
}

로거와 달리 추가가 아닌 기본 핸들러를 대체하여 핸들러를 등록합니다.

config.Services.Replace(typeof(IExceptionHandler),
    new OopsExceptionHandler(config.Services.GetExceptionHandler()));


답변

내 질문에 답하기 위해 이것은 불가능합니다!

내부 서버 오류를 일으키는 모든 예외를 처리하는 것은 Web API가 가져야하는 기본 기능처럼 보이므로 Microsoft 에 Web API에 대한 글로벌 오류 처리기를 요청했습니다 .

https://aspnetwebstack.codeplex.com/workitem/1001

동의하면 해당 링크로 이동하여 투표하십시오!

한편, 훌륭한 기사 인 ASP.NET Web API Exception Handling 은 몇 가지 다른 범주의 오류를 포착하는 몇 가지 방법을 보여줍니다. 해야 할 것보다 더 복잡하고 모든 것을 잡을 수는 없습니다. 내부 서버 오류를 못하지만 오늘날 사용할 수있는 최선의 접근 방식입니다.

업데이트 : 이제 전역 오류 처리가 구현되어 야간 빌드에서 사용할 수 있습니다! ASP.NET MVC v5.1에서 출시 될 예정입니다. 작동 방식은 다음과 같습니다. https://aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling


답변

IExceptionHandler인터페이스 를 구현 하거나 ExceptionHandler기본 클래스를 상속하여 전역 예외 처리기를 만들 수도 있습니다 . 모든 등록 후 실행 체인에서 마지막으로 호출됩니다 IExceptionLogger.

IExceptionHandler는 모든 컨트롤러에서 처리되지 않은 모든 예외를 처리합니다. 이것은 목록의 마지막입니다. 예외가 발생하면 IExceptionLogger가 먼저 호출되고 컨트롤러 ExceptionFilter가 호출되고 여전히 처리되지 않은 경우 IExceptionHandler 구현이 호출됩니다.

public class OopsExceptionHandler : ExceptionHandler
{
    public override void HandleCore(ExceptionHandlerContext context)
    {
        context.Result = new TextPlainErrorResult
        {
            Request = context.ExceptionContext.Request,
            Content = "Oops! Sorry! Something went wrong."
        };
    }

    private class TextPlainErrorResult : IHttpActionResult
    {
        public HttpRequestMessage Request { get; set; }

        public string Content { get; set; }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            HttpResponseMessage response =
                             new HttpResponseMessage(HttpStatusCode.InternalServerError);
            response.Content = new StringContent(Content);
            response.RequestMessage = Request;
            return Task.FromResult(response);
        }
    }
}

여기 에 더 많은 것들이 있습니다 .


답변

알지 못하는 기존 try-catch 블록이있을 수 있습니다.

내 새 global.asax.Application_Error메서드가 레거시 코드에서 처리되지 않은 예외에 대해 일관되게 호출되지 않는다고 생각했습니다 .

그런 다음 예외 텍스트에서 Response.Write를 호출 한 호출 스택 중간에서 몇 개의 try-catch 블록을 발견했습니다. 그거였다. 화면에 텍스트를 버리고 예외 돌을 죽였습니다.

그래서 예외가 처리되고 있었지만 처리는 아무런 도움이되지 않았습니다. 일단 try-catch 블록을 제거하면 예상대로 Application_Error 메서드에 전파 된 예외가 발생합니다.


답변