我正在为客户端开发 API 服务层,并要求我在全局范围内捕获并记录所有错误。
因此,虽然像未知端点(或动作)这样的东西很容易通过使用 ELMAH 或添加类似这样的东西来处理Global.asax:
Global.asax
protected void Application_Error() { Exception unhandledException = Server.GetLastError(); //do more stuff }
. . .unhandled 与路由无关的错误不会被记录。例如:
public class ReportController : ApiController { public int test() { var foo = Convert.ToInt32("a");//Will throw error but isn't logged!! return foo; } }
我还尝试[HandleError]通过注册此过滤器来全局设置属性:
[HandleError]
filters.Add(new HandleErrorAttribute());
但这也不会记录所有错误。
如何拦截像/test上面调用产生的错误,以便我可以记录它们?似乎这个答案应该是显而易见的,但我已经尝试了到目前为止我能想到的一切。
/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]您可以跳过注册,只使用该属性装饰一个控制器。
[ExceptionHandling]
如果您的 Web API 托管在 ASP.NET 应用程序中,Application_Error则将为代码中所有未处理的异常调用该事件,包括您显示的测试操作中的异常。所以你所要做的就是在 Application_Error 事件中处理这个异常。在您展示的示例代码中,您只处理类型的异常,HttpException这显然不是Convert.ToInt32("a")代码的情况。因此,请确保您在其中记录并处理所有异常:
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 } } }
Web API 中的异常处理可以在各个级别完成。以下是detailed article对不同可能性的解释:
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 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; }