asp.net web api-如何为C#MVC4 web api应用程序全局记录所有异常
本文关键字:web 全局 应用程序 记录 异常 api C#MVC4 api- net asp | 更新日期: 2023-09-27 18:01:43
背景
我正在为一个客户端开发一个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]
属性装饰单个控制器。
作为对先前答案的补充。
昨天,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);
}
}
如果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; } }
为什么要重新考虑etc?这是有效的,它将使服务返回状态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中,并记录未处理的异常,然后将其传递。除非有更好的内置方法。
以下是一个参考CatchAll(已处理或未处理(异常
(编辑:哦,API(