C # MVC4 WebAPI 앱에 대해 모든 예외를 전체적으로 어떻게 기록합니까?
배경
클라이언트를위한 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; } }
이전 답변에 추가로.
Yesterday, ASP.NET Web API 2.1 was oficially released.
It offers another opportunity to handle exceptions globally.
The details are given in the sample.
Briefly, you add global exception loggers and/or global exception handler (only one).
You add them to configuration:
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());
}
And their realization:
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);
}
}
Why rethrow etc? This works and it will make the service return status 500 etc
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);
}
}
have you thought about doing something like an handle error action filter like
[HandleError]
public class BaseController : Controller {...}
you can also create a custom version of [HandleError]
with which you can write error info and all other details to log
Wrap the whole thing in a try/catch and log the unhandled exception, then pass it on. Unless there's a better built-in way to do it.
Here's a reference Catch All (handled or unhandled) Exceptions
(edit: oh API)
'Programming' 카테고리의 다른 글
MySQL에서 기본 키 제거 (0) | 2020.05.25 |
---|---|
리눅스에서 Xcode를 실행할 수 있습니까?SQL Server 문자열을 날짜로 변환 (0) | 2020.05.25 |
JavaScript 카레 : 실용적인 응용 프로그램은 무엇입니까? (0) | 2020.05.25 |
Emacs 내에서 su / sudo가있는 파일 열기 (0) | 2020.05.25 |
NoClassDefFoundError : android.support.v7.internal.view.menu.MenuBuilder (0) | 2020.05.25 |