将请求范围对象注入MVC ActionFilterAttribute



我有一个购物车服务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(第章过滤器依赖注入

最新更新