哪一个优先,ASP.NET Web Api 2.0中的ExceptionFilter或ExceptionHandler?

时间:2015-01-24 15:27:56

标签: asp.net-web-api asp.net-web-api2 asp.net-web-api-filters

我的web api 2.0中有一个全局ExceptionHandler,它处理所有未处理的异常,以便向api调用者返回友好的错误消息。 我还有一个全局ExceptionFilter,它在我的web api中处理一个非常特殊的异常并返回一个特定的响应。 ExceptionFilter是通过插件动态添加到我的web api中的,因此我无法在ExceptionHandler中执行它的操作。

我想知道我是否同时全局注册了ExceptionHandler和ExceptionFilter,哪一个优先并先执行?现在我可以看到ExceptionFilter正在ExceptionHandler之前执行。而且我也可以在我的ExceptionFilter中看到,如果我创建了一个响应,则不会执行ExceptionHandler。

可以安全地假设:

  1. ExceptionFilters在ExceptionHandlers之前执行。

  2. 如果ExceptionFilter创建响应,则不会执行ExceptionHandler。

1 个答案:

答案 0 :(得分:29)

我必须通过System.Web.Http进行调试才能找到问题的答案。所以答案是:

  1. 可以安全地假设ExceptionFilters将在ExceptionHandlers之前执行

  2. 如果ExceptionFilter创建响应,则不会执行ExceptionHandler。

  3. 为什么会这样:

    当注册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,然后执行所有ExceptionFilters,然后如果executionContext.Response == null,则执行ExceptionHandler。

    我希望这很有用!