ASP.NET Web API跨请求缓存操作筛选器属性

Ste*_*ven 14 .net c# asp.net dependency-injection asp.net-web-api

在ASP.NET Web API(4.0.30506)中似乎有一些奇怪的行为,我以前没见过.

我所看到的是,相同的动作过滤器属性实例在Web API请求上重用.如果此属性将依赖项注入其中,这尤其是一个问题,因为这些依赖项可能特定于Web请求.我知道属性更好是被动的,但我的假设是动作过滤器属性没有被缓存.

我搜索了描述这个的任何文章,博客文章或微软更改日志及其背后的原因,但我找不到一件事.这让我想知道我的配置是否有问题导致这种情况发生.但是,我能够在一个新的,空的Visual Studio 2012 Web API项目中重现这个问题.

我所做的是使用带有"Web API"模板的Visual Studio 2012 ASP.NET MVC 4 Web应用程序项目创建一个新的空项目.它附带了Web API 4.0.20710.0 NuGet包.之后我添加了以下属性:

[DebuggerDisplay("{id}")]
public class TestFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute {
    private static readonly List<int> used = new List<int>();

    private static int counter;
    private readonly int id;

    public TestFilterAttribute() {
        this.id = Interlocked.Increment(ref counter);
    }

    public override void OnActionExecuting(HttpActionContext actionContext) {
        // Just for testing: I would expect this line never to throw, but it does.
        if (used.Contains(this.id)) throw new Exception("WAT?");
        used.Add(this.id);
        base.OnActionExecuting(actionContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

我将此属性添加到ValuesController(默认模板的一部分):

public class ValuesController : ApiController {
    // GET api/values
    [TestFilterAttribute]
    public IEnumerable<string> Get() {
        return new string[] { "value1", "value2" };
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

现在,当我启动项目时,转到浏览器中的/ api/values并刷新该页面几次,"WAT?" 抛出异常.

这是Web API的正常行为吗?如果是这样,这是什么原因?或者我在某处遗漏了一些有关此更改的备忘录?这是否使Web API属性更适合进行依赖注入?或者我做错了什么?

Mih*_*scu 18

Web API建立在MVC之上,因此它使用了很多功能.

属性实例可重用性是MVC 3引入的积极缓存的一部分.这意味着相同的Attribute实例最有可能与其应用的所有实例一起使用Actions.MVC管道将尽力将您的Attribute类视为一个Singleton.

因为重用了相同的Attribute 实例,所以不会调用它的构造函数,id也不会递增.例如,如果你id在里面增加OnActionExecuting,那么一切都会好起来的.

您仍然可以随心所欲地做任何事情Attribute.您只需要记住,不能保证始终可以创建新实例.该构造函数不应该包含什么,但最初的初始化.

public TestFilterAttribute() {
    // Instance will be reused thus this will not be called for each Action
}

public override void OnActionExecuting(HttpActionContext actionContext) {
    // Called on each Action
}
Run Code Online (Sandbox Code Playgroud)

  • 您无法使用属性执行所需操作.具体来说,由于此缓存,您无法正确使用请求范围依赖项的依赖项注入.此缓存破坏的一个常见情况是在身份验证过滤器中注入EF上下文. (4认同)