Web API过滤器未捕获从方法组

时间:2018-02-16 14:24:19

标签: c# linq asp.net-web-api exception-handling asp.net-web-api-filters

我正在使用WebApi。我的基本控制器上有自定义ActionFilter,全局添加了自定义ExceptionFilter。两者都继承自System.Web.Http.Filters命名空间中的关联FilterAttributes,而不是mvc版本。

我一直在我的一个服务中从私有方法抛出一个异常,这个方法就是resharper在Linq语句中使用它时调用方法组的东西(在本例中是select)。

public IEnumerable<Foo> GetFoos()
{
    IEnumerable<Bar> bars = _work.BarRepository.GetAll();

    //throw new Exception("I'm visible to the filters");

    IEnumerable<Foo> foos = bars.Select(MakeFooFromBar);

    return foos;
}

private Foo MakeFooFromBar(Bar bar)
{
    // an exception is being thrown here
    // which is not being caught by the filers
    throw new Exception("I am invisible to the filters");
}

这两个过滤器都没有捕获此异常(请参阅下面的过滤器)。我的动作过滤器说没有异常,我的异常过滤器永远不会被命中。如果我在Linq选择之前抛出一个异常(我已经注释掉了),那么就会按预期捕获异常。

使用fiddler,我最终得到的是:

{  
   "message":"An error has occurred.",
   "exceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.",
   "exceptionType":"System.InvalidOperationException",
   "stackTrace":null,
   "innerException":{  
      "message":"An error has occurred.",
      "exceptionMessage":"I am invisible to the filters",
      "exceptionType":"System.Exception",
      "stackTrace":""
   }
}

我的动作过滤器的一部分:

public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
    Exception exception = actionExecutedContext.Exception;

    if (exception == null)
    {
        // do things
    }
    else
    {
        // do some other things
    }
}

和我的异常过滤器的一部分:

public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
    // return early on certain kinds of exceptions...

    _loggedErrorService.Log(actionExecutedContext.Exception);
}

1 个答案:

答案 0 :(得分:1)

来自documentation

  

您可以通过编写异常过滤器来自定义Web API处理异常的方式。当控制器方法抛出任何未处理的异常[...]

时,将执行异常过滤器

问题是,如果从WebAPI方法返回IEnumerable<T>,则在序列化期间,当IEnumerable<T>被迭代时,将发生错误。这是Select(以及大多数其他查询运算符)的标准行为,它只调用迭代时传递给它的方法(在本例中为MakeFooFromBar),因此在调用{时不会抛出异常{1}}但很久以后。

您可以添加Select以使异常在您的方法中发生。