所以,我们一直在寻找创建一个IApiFilter来做一些事前和发布信息的日志,但是我们遇到了一个看起来像是一个bug的问题。
我们创建了一个扩展ActionFilterAttribute(System.Web.HttpFilters)的类,长话短说,将它的内容留空,这样它只是从它的基类继承而来:
public class ApiLoggingFilter : ActionFilterAttribute, IApiFilterProvider
{
}
调试时,我们点击了OrchardApiActionFilterDispatcher(Orchard.WebApi.Filters),过滤器发送到actionFilter.ExecuteActionFilterAsync(...)
这很快导致StackOverflowException,因为我们的Filter中没有任何新内容,问题必须在于调度程序和过滤器之间的交互。
在调查这个问题的同时,我们提出了一些相关的事情。我们还尝试创建一个扩展ExceptionFilterAttribute
的类,并且此功能已成功完成。
深入研究这一领域,我们发现两者之间存在重大差异。 IExceptionFilter
(ExceptionFilterAttribute
实现的)具有以下签名:
Task ExecuteExceptionFilterAsync(
HttpActionExecutedContext actionExecutedContext,
CancellationToken cancellationToken
);
IActionFilter
(ActionFilterAttribute
实现)具有略微扩展的签名的位置:
Task<HttpResponseMessage> ExecuteActionFilterAsync(
HttpActionContext actionContext,
CancellationToken cancellationToken,
Func<Task<HttpResponseMessage>> continuation
);
这里的最大区别是传入的Func<Task<HttpResponseMessage>> continuation
。就个人而言,我推测这是作为基于以下行OrchardApiActionFilterDispatcher
装饰的过滤器操作的总和传入的:< / p>
continuation = () => actionFilter.ExecuteActionFilterAsync(
actionContext, cancellationToken, continuation
);
因此,它似乎进入过滤器并从过滤器中调用continutaion()。通过ActionFilterAttribute
中的一些私有方法深入挖掘,我们最终找到:
HttpResponseMessage response = await continutaion();
看到这是所有过滤器调用的堆栈,调用它实质上再次调用过滤器堆栈的顶部并对刚刚进行的过滤器进行相同的调用。这种情况持续无限,直到我们最终出现堆栈溢出。
Orchard(或StackOverflow的世界)中是否有人对此事有任何想法?我们只是错误地使用这些过滤器吗?我们错过了什么吗?或者这只是一个需要解决的错误?