我的web api 2.0中有一个全局ExceptionHandler,它处理所有未处理的异常,以便向api调用者返回一个友好的错误消息.
我也有一个全局ExceptionFilter,它处理一个非常特殊的异常在我的web api并返回一个具体的响应. ExceptionFilter由插件动态地添加到我的web api中,所以我不能在我的ExceptionHandler中执行它.
我也有一个全局ExceptionFilter,它处理一个非常特殊的异常在我的web api并返回一个具体的响应. ExceptionFilter由插件动态地添加到我的web api中,所以我不能在我的ExceptionHandler中执行它.
我想知道我是否在全球注册了ExceptionHandler和ExceptionFilter,哪一个将优先执行,首先执行?现在我可以看到ExceptionFilter正在执行ExceptionHandler之前.我也可以看到,在我的ExceptionFilter中,如果我创建一个响应,ExceptionHandler没有被执行.
假设这样做是安全的:
> ExceptionFilter在ExceptionHandler之前执行.
>如果ExceptionFilter创建一个响应,则ExceptionHandler将不被执行.
解决方法
我不得不通过System.Web.Http进行调试,以便找到我的问题的答案.所以答案是:
>可以安全地假设ExceptionFilters将在ExceptionHandler之前执行
>如果ExceptionFilter创建一个响应,ExceptionHandler将不会被执行.
为什么是这样的:
当您将ExceptionFilter注册为全局执行或用于控制器操作时,所有api控制器继承的ApiController基类都将将结果包装到一个ExceptionFilterResult中,并调用其ExecuteAsync方法.这是ApiController中的代码,它是这样做的:
if (exceptionFilters.Length > 0) { IExceptionLogger exceptionLogger = ExceptionServices.GetLogger(controllerServices); IExceptionHandler exceptionHandler = ExceptionServices.GetHandler(controllerServices); result = new ExceptionFilterResult(ActionContext,exceptionFilters,exceptionLogger,exceptionHandler,result); } return result.ExecuteAsync(cancellationToken);
看看ExceptionFilterResult.ExecuteAsync方法:
try { return await _innerResult.ExecuteAsync(cancellationToken); } catch (Exception e) { exceptionInfo = ExceptionDispatchInfo.Capture(e); } // This code path only runs if the task is faulted with an exception Exception exception = exceptionInfo.SourceException; Debug.Assert(exception != null); bool isCancellationException = exception is OperationCanceledException; ExceptionContext exceptionContext = new ExceptionContext( exception,ExceptionCatchBlocks.IExceptionFilter,_context); if (!isCancellationException) { // We don't log cancellation exceptions because it doesn't represent an error. await _exceptionLogger.LogAsync(exceptionContext,cancellationToken); } HttpActionExecutedContext executedContext = new HttpActionExecutedContext(_context,exception); // Note: exception filters need to be scheduled in the reverse order so that // the more specific filter (e.g. Action) executes before the less specific ones (e.g. Global) for (int i = _filters.Length - 1; i >= 0; i--) { IExceptionFilter exceptionFilter = _filters[i]; await exceptionFilter.ExecuteExceptionFilterAsync(executedContext,cancellationToken); } if (executedContext.Response == null && !isCancellationException) { // We don't log cancellation exceptions because it doesn't represent an error. executedContext.Response = await _exceptionHandler.HandleAsync(exceptionContext,cancellationToken); }
您可以看到先执行ExceptionLogger,然后执行所有ExceptionFilter,然后如果executionContext.Response == null,则执行ExceptionHandler.
我希望这是有用的!