我正在为客户开发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());
}
}
OR 您可以跳过注册,只使用[ExceptionHandling]
属性装饰一个控制器。
答案 0 :(得分:76)
作为以前答案的补充。
昨天,ASP.NET Web API 2.1正式released 它提供了另一个处理全球异常的机会 详细信息在sample中给出。
简而言之,您添加全局异常记录器和/或全局异常处理程序(仅一个) 您将它们添加到配置:
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);
}
}
答案 1 :(得分:55)
如果您的Web 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
}
}
}
击> <击> 撞击>
Web 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;
}
}
答案 2 :(得分:7)
为什么要重新抛出?这有效,它将使服务返回状态为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);
}
}
答案 3 :(得分:2)
您是否考虑过像
这样的句柄错误操作过滤器[HandleError]
public class BaseController : Controller {...}
您还可以创建[HandleError]
的自定义版本,您可以使用该版本编写错误信息和所有其他详细信息以进行记录
答案 4 :(得分:1)
将整个事物包装在try / catch中并记录未处理的异常,然后将其传递给它。除非有更好的内置方式来实现它。
以下是参考Catch All (handled or unhandled) Exceptions
(编辑:哦API)