WebApi v2 ExceptionHandler未调用

为什么永远不会调用自定义ExceptionHandler ,而是返回标准响应(不是我想要的那个)?

像这样注册

 config.Services.Add(typeof(IExceptionLogger), new ElmahExceptionLogger()); config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler()); 

并实施这样的

 public class GlobalExceptionHandler : ExceptionHandler { public override void Handle(ExceptionHandlerContext context) { context.Result = new ExceptionResponse { statusCode = context.Exception is SecurityException ? HttpStatusCode.Unauthorized : HttpStatusCode.InternalServerError, message = "An internal exception occurred. We'll take care of it.", request = context.Request }; } } public class ExceptionResponse : IHttpActionResult { public HttpStatusCode statusCode { get; set; } public string message { get; set; } public HttpRequestMessage request { get; set; } public Task ExecuteAsync(CancellationToken cancellationToken) { var response = new HttpResponseMessage(statusCode); response.RequestMessage = request; response.Content = new StringContent(message); return Task.FromResult(response); } } 

并抛出这样(测试)

 throw new NullReferenceException("testerror"); 

在控制器或存储库中。

UPDATE

我没有另一个ExceptionFilter

我找到了这种行为的触发器:

给定URL

 GET http://localhost:XXXXX/template/lock/someId 

发送此标头,我的ExceptionHandler工作

 Host: localhost:XXXXX 

发送此标头,它不起作用,内置处理程序返回错误

 Host: localhost:XXXXX Origin: http://localhost:YYYY 

这可能是CORS请求的问题(我使用带有通配符的全局WebAPI CORS包)或最终使用我的ELMAH记录器。 它也发生在Azure(网站)上托管,尽管内置的error handling程序是不同的。

知道如何解决这个问题吗?

原来,默认只处理最外层的exception,而不是存储库类中的exception。 所以下面也必须被覆盖:

 public virtual bool ShouldHandle(ExceptionHandlerContext context) { return context.ExceptionContext.IsOutermostCatchBlock; } 

更新1

WebAPI v2不再使用IsOutermostCatchBlock 。 无论如何,我的实现没有任何变化,因为ShouldHandle的新代码仍然阻止了我的error handling程序。 所以我正在使用它,我的error handling程序被调用一次。 我通过这种方式捕获控制器和存储库中的错误。

 public virtual bool ShouldHandle(ExceptionHandlerContext context) { return true; } 

更新2

由于这个问题引起了如此多的关注,请注意当前的解决方案是@JustAMartin在下面的评论中链接的解决方案。

这里真正的罪魁祸首是在消息处理pipline中通过EnableCors方法插入的CorsMessageHandler。 catch块拦截任何exception并在它到达HTTPServer try-catch块之前转换为响应,并且可以调用ExceptionHandler逻辑

 protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { CorsRequestContext corsRequestContext = request.GetCorsRequestContext(); HttpResponseMessage result; if (corsRequestContext != null) { try { if (corsRequestContext.IsPreflight) { result = await this.HandleCorsPreflightRequestAsync(request, corsRequestContext, cancellationToken); return result; } result = await this.HandleCorsRequestAsync(request, corsRequestContext, cancellationToken); return result; } catch (Exception exception) { result = CorsMessageHandler.HandleException(request, exception); return result; } } result = await this.<>n__FabricatedMethod3(request, cancellationToken); return result; }