C# 捕获 ASP.NET Web Api 中所有未处理的异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16028919/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
catch all unhandled exceptions in ASP.NET Web Api
提问by Joe Daley
How do I catch allunhandled exceptions that occur in ASP.NET Web Api so that I can log them?
如何捕获ASP.NET Web Api 中发生的所有未处理的异常,以便我可以记录它们?
So far I have tried:
到目前为止,我已经尝试过:
- Create and register an
ExceptionHandlingAttribute - Implement an
Application_Errormethod inGlobal.asax.cs - Subscribe to
AppDomain.CurrentDomain.UnhandledException - Subscribe to
TaskScheduler.UnobservedTaskException
- 创建并注册一个
ExceptionHandlingAttribute - 实现一个
Application_Error方法Global.asax.cs - 订阅
AppDomain.CurrentDomain.UnhandledException - 订阅
TaskScheduler.UnobservedTaskException
The ExceptionHandlingAttributesuccessfully handles exceptions that are thrown within controller action methods and action filters, but other exceptions are not handled, for example:
在ExceptionHandlingAttribute成功处理时引发的控制器操作方法和操作筛选范围内,但其他异常没有被处理,例如例外:
- Exceptions thrown when an
IQueryablereturned by an action method fails to execute - Exceptions thrown by a message handler (i.e.
HttpConfiguration.MessageHandlers) - Exceptions thrown when creating a controller instance
IQueryable动作方法返回的a执行失败时抛出的异常- 消息处理程序抛出的异常(即
HttpConfiguration.MessageHandlers) - 创建控制器实例时抛出的异常
Basically, if an exception is going to cause a 500 Internal Server Error to be returned to the client, I want it logged. Implementing Application_Errordid this job well in Web Forms and MVC - what can I use in Web Api?
基本上,如果异常将导致 500 Internal Server Error 返回给客户端,我希望将其记录下来。Application_Error在 Web Forms 和 MVC 中实现这项工作做得很好 - 我可以在 Web Api 中使用什么?
采纳答案by decates
This is now possible with WebAPI 2.1 (see the What's New):
现在可以使用 WebAPI 2.1(请参阅新增功能):
Create one or more implementations of IExceptionLogger. For example:
创建 IExceptionLogger 的一个或多个实现。例如:
public class TraceExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
Trace.TraceError(context.ExceptionContext.Exception.ToString());
}
}
Then register with your application's HttpConfiguration, inside a config callback like so:
然后在您的应用程序的 HttpConfiguration 中注册一个配置回调,如下所示:
config.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());
or directly:
或直接:
GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());
回答by Joe Daley
To answer my own question, this isn't possible!
要回答我自己的问题,这是不可能的!
Handling all exceptions that cause internal server errors seems like a basic capability Web API should have, so I have put in a request with Microsoft for a Global error handler for Web API:
处理所有导致内部服务器错误的异常似乎是 Web API 应该具备的基本功能,因此我已向 Microsoft 提出请求,要求为 Web API提供全局错误处理程序:
https://aspnetwebstack.codeplex.com/workitem/1001
https://aspnetwebstack.codeplex.com/workitem/1001
If you agree, go to that link and vote for it!
如果您同意,请转到该链接并为其投票!
In the meantime, the excellent article ASP.NET Web API Exception Handlingshows a few different ways to catch a few different categories of error. It's more complicated than it should be, and it doesn't catch allinteral server errors, but it's the best approach available today.
同时,优秀文章ASP.NET Web API 异常处理展示了几种不同的方法来捕获几种不同类别的错误。它比它应有的更复杂,它不能捕获所有内部服务器错误,但它是当今可用的最佳方法。
Update:Global error handling is now implemented and available in the nightly builds! It will be released in ASP.NET MVC v5.1. Here's how it will work: https://aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling
更新:全局错误处理现已实现并在每晚构建中可用!它将在 ASP.NET MVC v5.1 中发布。以下是它的工作原理:https: //aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling
回答by Yuval Itzchakov
You can also create a global exception handler by implementing the IExceptionHandlerinterface (or inherit the ExceptionHandlerbase class). It will be the last to be called in the execution chain, after all registered IExceptionLogger:
您还可以通过实现IExceptionHandler接口(或继承ExceptionHandler基类)来创建全局异常处理程序。在所有注册之后,它将是执行链中最后一个被调用的IExceptionLogger:
The IExceptionHandler handles all unhandled exceptions from all controllers. This is the last in the list. If an exception occurs, the IExceptionLogger will be called first, then the controller ExceptionFilters and if still unhandled, the IExceptionHandler implementation.
IExceptionHandler 处理来自所有控制器的所有未处理的异常。这是列表中的最后一个。如果发生异常,将首先调用 IExceptionLogger,然后调用控制器 ExceptionFilters,如果仍未处理,则调用 IExceptionHandler 实现。
public class OopsExceptionHandler : ExceptionHandler
{
public override void HandleCore(ExceptionHandlerContext context)
{
context.Result = new TextPlainErrorResult
{
Request = context.ExceptionContext.Request,
Content = "Oops! Sorry! Something went wrong."
};
}
private class TextPlainErrorResult : IHttpActionResult
{
public HttpRequestMessage Request { get; set; }
public string Content { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response =
new HttpResponseMessage(HttpStatusCode.InternalServerError);
response.Content = new StringContent(Content);
response.RequestMessage = Request;
return Task.FromResult(response);
}
}
}
More on that here.
更多关于这里。
回答by Duoc Tran
The Yuval's answer is for customizing responses to unhandled exceptions caught by Web API, not for logging, as noted on the linked page. Refer to the When to Use section on the page for details. The logger is always called but the handler is called only when a response can be sent. In short, use the loggerto log and the handler to customize the response.
Yuval 的答案是用于自定义对 Web API 捕获的未处理异常的响应,而不是用于日志记录,如链接页面所述。有关详细信息,请参阅页面上的“何时使用”部分。记录器总是被调用,但只有在可以发送响应时才调用处理程序。简而言之,使用记录器记录日志和处理程序来自定义响应。
By the way, I am using assembly v5.2.3 and the ExceptionHandlerclass does not have the HandleCoremethod. The equivalent, I think, is Handle. However, simply subclassing ExceptionHandler(as in Yuval's answer) does not work. In my case, I have to implement IExceptionHandleras follows.
顺便说一下,我使用的是程序集 v5.2.3 并且ExceptionHandler该类没有该HandleCore方法。我认为,等价物是Handle。但是,简单的子类化ExceptionHandler(如 Yuval 的回答)是行不通的。就我而言,我必须IExceptionHandler按如下方式实施。
internal class OopsExceptionHandler : IExceptionHandler
{
private readonly IExceptionHandler _innerHandler;
public OopsExceptionHandler (IExceptionHandler innerHandler)
{
if (innerHandler == null)
throw new ArgumentNullException(nameof(innerHandler));
_innerHandler = innerHandler;
}
public IExceptionHandler InnerHandler
{
get { return _innerHandler; }
}
public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
Handle(context);
return Task.FromResult<object>(null);
}
public void Handle(ExceptionHandlerContext context)
{
// Create your own custom result here...
// In dev, you might want to null out the result
// to display the YSOD.
// context.Result = null;
context.Result = new InternalServerErrorResult(context.Request);
}
}
Note that, unlike the logger, you register your handler by replacing the default handler, not adding.
请注意,与记录器不同,您通过替换默认处理程序而不是添加来注册处理程序。
config.Services.Replace(typeof(IExceptionHandler),
new OopsExceptionHandler(config.Services.GetExceptionHandler()));
回答by Resource
You may have existing try-catch blocks that you're not aware of.
您可能有您不知道的现有 try-catch 块。
I thought my new global.asax.Application_Errormethod wasn't being consistently called for unhandled exceptions in our legacy code.
我认为我的新global.asax.Application_Error方法在我们的遗留代码中没有始终如一地被调用来处理未处理的异常。
Then I found a few try-catch blocks in the middle of the call stack that called Response.Write on the Exception text. That was it. Dumped the text on the screen then killed the exception stone dead.
然后我在调用堆栈中间发现了一些 try-catch 块,它们在 Exception 文本上调用了 Response.Write。就是这样。在屏幕上倾倒文字然后杀死异常石头死了。
So the exceptions were being handled, but the handling was doing nothing useful. Once I removed those try-catch blocks the exceptions propagated to the Application_Error method as expected.
因此正在处理异常,但处理没有做任何有用的事情。一旦我删除了那些 try-catch 块,异常就会按预期传播到 Application_Error 方法。

