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; }