【问题标题】:Which one takes priority, ExceptionFilter or ExceptionHandler in ASP.NET Web Api 2.0?ASP.NET Web Api 2.0 中哪个优先,ExceptionFilter 还是 ExceptionHandler?
【发布时间】:2015-03-23 12:05:22
【问题描述】:

我的 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 将不会被执行。

【问题讨论】:

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


    【解决方案1】:

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

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

    2. 如果 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,如果executeContext.Response == null,则执行ExceptionHandler。

    希望对你有用!

    【讨论】:

    • 很棒的反应!感谢您的挖掘!
    猜你喜欢
    • 2019-06-15
    • 2012-02-26
    • 1970-01-01
    • 1970-01-01
    • 2016-11-02
    • 2013-04-20
    • 1970-01-01
    • 2015-01-06
    • 2010-12-17
    相关资源
    最近更新 更多