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

时间:2014-12-25 10:05:54

标签: c# asp.net .net asp.net-web-api dependency-injection

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

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

我搜索了描述此内容的任何文章,博客文章或Microsoft更改日志及其背后的原因,但我找不到任何一件事。这让我想知道我的配置是否有问题导致这种情况发生。但是,我能够在一个新的空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);
    }
}

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

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

    // ...
}

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

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

1 个答案:

答案 0 :(得分:16)

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
}