배경
클라이언트를위한 API 서비스 계층을 개발 중이며 전 세계적으로 모든 오류를 포착하고 기록하도록 요청되었습니다.
따라서 ELMAH를 사용하거나 다음과 같은 것을 추가하면 알 수없는 끝점 (또는 동작)과 같은 것이 쉽게 처리됩니다 Global.asax
.
protected void Application_Error()
{
Exception unhandledException = Server.GetLastError();
//do more stuff
}
. . 라우팅과 관련이없는 처리되지 않은 오류는 기록되지 않습니다. 예를 들면 다음과 같습니다.
public class ReportController : ApiController
{
public int test()
{
var foo = Convert.ToInt32("a");//Will throw error but isn't logged!!
return foo;
}
}
[HandleError]
이 필터를 등록 하여 속성을 전체적으로 설정하려고 시도했습니다 .
filters.Add(new HandleErrorAttribute());
그러나 모든 오류를 기록하지는 않습니다.
문제 / 질문
/test
위에서 호출하여 생성 된 오류와 같은 오류를 어떻게 가로 채서 기록 할 수 있습니까? 이 대답은 분명해야하지만 지금까지 생각할 수있는 모든 것을 시도했습니다.
이상적으로는 요청하는 사용자의 IP 주소, 날짜, 시간 등과 같은 오류 로깅에 몇 가지 사항을 추가하고 싶습니다. 또한 오류가 발생하면 지원 담당자에게 자동으로 전자 메일을 보내려고합니다. 이 오류가 발생할 때만 이러한 오류를 가로 챌 수있는 경우이 모든 작업을 수행 할 수 있습니다.
해결되었습니다!
대답을 수락 한 Darin Dimitrov 덕분에 나는 이것을 알아 냈습니다. WebAPI는 일반 MVC 컨트롤러와 같은 방식으로 오류를 처리 하지 않습니다 .
다음은 효과가 있습니다.
1) 네임 스페이스에 사용자 정의 필터를 추가하십시오.
public class ExceptionHandlingAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is BusinessException)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message),
ReasonPhrase = "Exception"
});
}
//Log Critical errors
Debug.WriteLine(context.Exception);
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("An error occurred, please try again or contact the administrator."),
ReasonPhrase = "Critical Exception"
});
}
}
2) 이제 WebApiConfig 클래스 에 필터를 전체적으로 등록하십시오 .
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
config.Filters.Add(new ExceptionHandlingAttribute());
}
}
또는 등록을 건너 뛰고 [ExceptionHandling]
속성 으로 단일 컨트롤러를 장식 할 수 있습니다 .
답변
웹 API가 ASP.NET 응용 프로그램 내에서 호스팅되는 경우 표시 Application_Error
한 테스트 작업의 예외를 포함하여 코드에서 처리되지 않은 모든 예외에 대해 이벤트가 호출됩니다. 따라서 Application_Error 이벤트 내에서이 예외를 처리하기 만하면됩니다. 샘플 코드 HttpException
에서 Convert.ToInt32("a")
코드 의 경우가 아닌 유형의 예외 만 처리하고 있음을 보여주었습니다 . 따라서 모든 예외를 기록하고 처리해야합니다.
protected void Application_Error()
{
Exception unhandledException = Server.GetLastError();
HttpException httpException = unhandledException as HttpException;
if (httpException == null)
{
Exception innerException = unhandledException.InnerException;
httpException = innerException as HttpException;
}
if (httpException != null)
{
int httpCode = httpException.GetHttpCode();
switch (httpCode)
{
case (int)HttpStatusCode.Unauthorized:
Response.Redirect("/Http/Error401");
break;
// TODO: don't forget that here you have many other status codes to test
// and handle in addition to 401.
}
else
{
// It was not an HttpException. This will be executed for your test action.
// Here you should log and handle this case. Use the unhandledException instance here
}
}
}
웹 API의 예외 처리는 다양한 수준에서 수행 될 수 있습니다. 다음 detailed article
은 다양한 가능성을 설명합니다.
-
글로벌 예외 필터로 등록 될 수있는 사용자 정의 예외 필터 속성
[AttributeUsage(AttributeTargets.All)] public class ExceptionHandlingAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext context) { if (context.Exception is BusinessException) { throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(context.Exception.Message), ReasonPhrase = "Exception" }); } //Log Critical errors Debug.WriteLine(context.Exception); throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent("An error occurred, please try again or contact the administrator."), ReasonPhrase = "Critical Exception" }); } }
-
맞춤 액션 호출자
public class MyApiControllerActionInvoker : ApiControllerActionInvoker { public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken) { var result = base.InvokeActionAsync(actionContext, cancellationToken); if (result.Exception != null && result.Exception.GetBaseException() != null) { var baseException = result.Exception.GetBaseException(); if (baseException is BusinessException) { return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(baseException.Message), ReasonPhrase = "Error" }); } else { //Log critical error Debug.WriteLine(baseException); return Task.Run<HttpResponseMessage>(() => new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(baseException.Message), ReasonPhrase = "Critical Error" }); } } return result; } }
답변
이전 답변에 추가로.
어제 ASP.NET Web API 2.1이 공개적으로 발표되었습니다 .
전 세계적으로 예외를 처리 할 수있는 또 다른 기회를 제공합니다.
자세한 내용은 샘플 에 나와 있습니다 .
간단히, 전역 예외 로거 및 / 또는 전역 예외 처리기 (하나만)를 추가합니다.
구성에 추가하십시오.
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
// There can be multiple exception loggers.
// (By default, no exception loggers are registered.)
config.Services.Add(typeof(IExceptionLogger), new ElmahExceptionLogger());
// There must be exactly one exception handler.
// (There is a default one that may be replaced.)
config.Services.Replace(typeof(IExceptionHandler), new GenericTextExceptionHandler());
}
그리고 그들의 실현 :
public class ElmahExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
...
}
}
public class GenericTextExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
context.Result = new InternalServerErrorTextPlainResult(
"An unhandled exception occurred; check the log for more information.",
Encoding.UTF8,
context.Request);
}
}
답변
왜 다시 던질까요? 이것은 작동하며 서비스 반환 상태를 500 등으로 만듭니다.
public class LogExceptionFilter : ExceptionFilterAttribute
{
private static readonly ILog log = LogManager.GetLogger(typeof (LogExceptionFilter));
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
log.Error("Unhandeled Exception", actionExecutedContext.Exception);
base.OnException(actionExecutedContext);
}
}
답변
핸들 에러 액션 필터와 같은 것을하는 것에 대해 생각 했습니까?
[HandleError]
public class BaseController : Controller {...}
[HandleError]
오류 정보 및 기타 모든 세부 정보를 기록 할 수 있는 사용자 지정 버전을 만들 수도 있습니다.
답변
모든 것을 try / catch로 감싸고 처리되지 않은 예외를 기록한 다음 전달하십시오. 더 나은 기본 제공 방법이 없다면.
다음은 모두 처리 된 (처리 된 또는 처리되지 않은) 예외를 참조합니다.
(편집 : 오 API)