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

本文关键字:操作 筛选 属性 缓存 请求 NET Web API ASP | 更新日期: 2023-09-27 18:35:13

Web

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

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

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

我所做的是使用Visual Studio 2012 ASP.NET MVC 4 Web应用程序项目和"Web API"模板创建一个新的空项目。它附带 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 属性特别不适合执行依赖项注入?还是我做错了什么?

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

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

属性实例可重用性是 MVC 3 引入的主动缓存的一部分。这意味着同一Attribute实例很可能会与应用它的所有Actions一起使用。MVC 管道将尽最大努力尝试将您的Attribute类视为Singleton

由于重用了同一个 Attribute 实例,因此不会调用它的构造函数,也不会递增id。例如,如果您在 OnActionExecuting 内递增id,一切都会很好。

您仍然可以用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
}