在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属性更适合进行依赖注入?或者我做错了什么?
答案 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
}