简体   繁体   English

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

[英]ASP.NET Web API caches action filter attributes across requests

There seems to be some weird behavior in ASP.NET Web API (4.0.30506) that I haven't witnessed before. 在ASP.NET Web API(4.0.30506)中似乎有一些奇怪的行为,我以前没见过。

What I'm seeing is that the same action filter attribute instance is reused over Web API requests. 我所看到的是,在Web API请求上重用了相同的动作过滤器属性实例。 This is especially a problem in case this attribute gets dependencies injected to it, since those dependencies might be specific to the web request. 如果此属性将依赖项注入其中,这尤其是一个问题,因为这些依赖项可能特定于Web请求。 I'm aware that it's better for attributes to be passive , but my assumption was that action filter attributes where not cached. 我知道属性更好是被动的 ,但我的假设是动作过滤器属性没有被缓存。

I searched for any articles, blog posts or Microsoft change logs that described this and the reason behind this, but I couldn't find a single thing. 我搜索了描述这个的任何文章,博客文章或微软更改日志及其背后的原因,但我找不到一件事。 That makes me wonder whether there is something wrong with my configuration that makes this happening. 这让我想知道我的配置是否有问题导致这种情况发生。 Thing is however, that I'm able to reproduce this issue in a new and empty Visual Studio 2012 Web API project. 但是,我能够在一个新的,空的Visual Studio 2012 Web API项目中重现这个问题。

What I did was create a new empty project using the Visual Studio 2012 ASP.NET MVC 4 Web Application project with the "Web API" template. 我所做的是使用带有“Web API”模板的Visual Studio 2012 ASP.NET MVC 4 Web应用程序项目创建一个新的空项目。 It comes with the Web API 4.0.20710.0 NuGet package. 它附带了Web API 4.0.20710.0 NuGet包。 After that I added the following attribute: 之后我添加了以下属性:

[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);
    }
}

And I add this attribute to the ValuesController (part of the default template): 我将此属性添加到ValuesController (默认模板的一部分):

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

    // ...
}

Now when I start the project, go to the /api/values in the browser and refresh that page a few times, the "WAT?" 现在,当我启动项目时,转到浏览器中的/ api / values并刷新该页面几次,“WAT?” exception is thrown. 抛出异常。

Is this normal behavior of Web API and if so, what's the reasoning about this? 这是Web API的正常行为吗?如果是这样,这是什么原因? Or Did I miss some memo about this change somewhere? 或者我在某处遗漏了一些有关此更改的备忘录? Does this make Web API attributes extra unsuited for doing dependency injection? 这是否使Web API属性更适合进行依赖注入? Or am I'm doing something wrong? 或者我做错了什么?

Web API is built on top of MVC , thus it uses a lot of it's functionality. Web API建立在MVC之上,因此它使用了很多功能。

Attribute instance re-usability is part of the aggressive caching introduced by MVC 3 . 属性实例可重用性是MVC 3引入的积极缓存的一部分。 This means that the same Attribute instance will most likely be used with all the Actions it is applied on. 这意味着相同的Attribute实例最有可能与其应用的所有Actions一起使用。 MVC pipeline will do it's best at trying to treat your Attribute class like a Singleton . MVC管道将尽力将您的Attribute类视为Singleton

Because the same Attribute instance is reused, it's Constructor is not called and id is not incremented. 因为重用了相同的Attribute 实例 ,所以不会调用Constructor ,也不会增加id If, for example, you increment id inside OnActionExecuting , all will work well. 例如,如果你在OnActionExecuting增加id ,那么一切都会正常工作。

You can still do everything you want with your Attribute . 您仍然可以使用Attribute执行所需的任何操作。 You only need to keep in mind that you are not guaranteed to always get a new instance created. 您只需要记住,不能保证始终可以创建新实例 The constructor shouldn't contain anything but initial initialization. 构造函数不应包含除初始初始化之外的任何内容。

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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM