我有一个购物车服务IShoppingCartService
,它被Ninject定义为InRequestScope
this.Bind<IShoppingCartService>().To<ShoppingCartService>().InRequestScope();
它加载用户的购物车并在内部缓存。一旦请求结束,服务对象就会消失。
我需要访问ActionFilter
中的购物车,所以我使用了[Inject]
属性。
public class MyActionFilterAttribute : ActionFilterAttribute
{
[Inject]
public IShoppingCartService ShoppingCartService
{
get; set;
}
}
然后我可以在像这样的动作过滤器中使用它
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var cart = ShoppingCartService.ShoppingCart;
...
}
现在是奇怪的部分。这已经运行了一年多了,然后突然(在最近升级了Ninject和MVC之后)我注意到购物车正在缓存(即不是InRequestScope
)。
在进一步的研究中,我发现ActionFilters是singleton(我验证了这一点,因为构造函数只被调用过一次)。因此,一旦加载了购物车的实例,它就会被永远锁定。
所以我的问题是——这到底是怎么回事?最近在Ninject或MVC中做了一些更改,这些更改本来可以让它在以前工作。
我现在的解决方案是执行以下操作:
public IShoppingCartService ShoppingCartService
{
get
{
var scs = (IShoppingCartService) DependencyResolver.Current.GetService(typeof(IShoppingCartService));
return scs;
}
}
不过,我真的很困惑,这是怎么回事——而且确实如此。我该怎么办?
也许虽然filter属性只实例化过一次,但每次页面命中时,属性都是[Injected]
。但让我们向前看:)
2010年,在Ninject.MVCx
(x=3,5,..)中实现了一种"新"的方法,即如何将内容注入动作过滤器。它不需要依赖于属性,并且支持构造函数注入。以下是它的样子:
(公平警告:我通常不做asp.net开发,如果以下内容确实改变了IActionFilter
的生命周期,我也没有尝试,所以你必须自己尝试。如果你尝试了,请提供反馈)
public class MyActionFilter : IActionFilter
{
private readonly IShoppingCartService shoppingCartService;
public MyActionFilter(IShoppingCartService shoppingCartService)
{
this.shoppingCartService = shoppingCartService;
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var cart = ShoppingCartService.ShoppingCart;
...
}
}
然后,滤波器需要通过特殊方法BindFilter
:进行绑定
this.BindFilter<MyActionFilter>(FilterScope.Action, 0)
.WhenControllerTypeIs<YourController>();
这将把它应用于CCD_ 10的所有动作。
还有其他目标你可以应用过滤器,通过使用:
// Is applied to all actions of controllers which have the FooAttribute
this.BindFilter<MyActionFilter>(FilterScope.Action, 0)
.WhenControllerHas<FooAttribute>();
// Is applied to all actions which have the FooAttribute
this.BindFilter<MyActionFilter>(FilterScope.Action, 0)
.WhenActionHas<FooAttribute>();
// Is applied to all actions named Index
this.BindFilter<MyActionFilter>(FilterScope.Action, 0)
.When((controllerContext, actionDescriptor) =>
actionDescriptor.ActionName == "Index");
关于这一点,可以在Remo Gloor的一篇伟大文章中找到更多信息:官方Ninject MVC扩展支持MVC3(第章过滤器依赖注入)