关于Ninject创建的MVC 3动作筛选器的生命周期的问题

6

我希望在我的MVC 3应用程序中使用Ninject的全局作用过滤器;但是,我想了解该过滤器的生命周期、其依赖关系以及如何通过装饰我的控制器和/或操作方法来引入其依赖关系的变化。

我希望我的过滤器类型依赖于绑定到请求范围的对象,因此类似于这样:

public sealed class MyGlobalActionFilter : IActionFilter
{
    public MyGlobalActionFilter(IService1 svc1, IService2 svc2, RequestType reqType)
    {
        // code here
    }

    // IActionFilter implementation here...
}

...在模块配置中...

Bind<IService1>().To<ConcreteService1>().InRequestScope()
Bind<IService2>().To<ConcreteService2>().InRequestScope()
BindFilter<MyGlobalActionFilter>(FilterScope.Global, null)
    .WhenControllerHas<RequestTypeAttribute>()
    .WithConstructorArgumentFromControllerAttribute<RequestTypeAttribute>(
        "reqType", 
        x => x.RequestType
    );
BindFilter<MyGlobalActionFilter>(FilterScope.Global, null)
    .WhenActionMethodHas<RequestTypeAttribute>()
    .WithConstructorArgumentFromActionAttribute<RequestTypeAttribute>(
        "reqType", 
        x => x.RequestType
    );
BindFilter<MyGlobalActionFilter>(FilterScope.Global)
    .When(x => true)
    .WithConstructorArgument("reqType", RequestType.Undefined)

在控制器和/或操作方法上设置一个属性,表示应用程序特定的“请求类型”:

[RequestType(RequestType.Type1)]
public sealed class SomeController : Controller { /* code here*/ }

我是否正确理解这个应该如何工作?每个HTTP请求都会创建并注入一个新的MyGlobalActionFilter实例吗?如果这样不行,那我漏掉了什么?有什么更好的方法来使其工作?
同时,使用注入的RequestType,在这里绑定过滤器的语法似乎过于冗长,我不确定它是否像我期望的那样工作,并且似乎有更好的方法可以在控制器或动作方法上没有RequestTypeAttribute时将默认RequestType注入到操作过滤器中。
请给我指点!
2个回答

4
我没有看到微软官方文档说明IFilterProvider何时以及多久被调用。但从我的观察来看,它似乎每个请求调用一次。这意味着瞬态绑定的过滤器基本上是InRequestScope绑定,不同之处在于它们不会在请求结束时被Ninject处理。
以下是需要进行的一些更改:
- 不要从ActionFilterAttribute派生,而是实现IActionFilter,以防止意外将其用作属性。 - 重新考虑使用FilterScope.Global进行所有绑定。我认为在全局优先级下运行具有操作/控制器的过滤器是不好的做法。 - 还要注意,为每个匹配绑定创建并执行一个过滤器。这意味着当前每个请求都会运行RequestType.Undefined的过滤器,无论操作或控制器上是否有属性。此外,如果它们上面有属性,则会执行操作和控制器的过滤器。

谢谢你的回答,Remo!我有一些后续问题:
  1. 你提到“重新考虑使用FilterScope.Global来绑定所有内容。我认为在具有全局优先级的操作/控制器上运行过滤器是不好的实践。”你能详细解释一下吗?
  2. 你会如何推荐实现一个全局操作过滤器,它可以从控制器和/或操作方法中以属性的形式消耗可选元数据?
- FMM

0
如果“System.Web.Mvc.GlobalFilters.Filters”是你所说的“全局作用域操作过滤器”,那么这些过滤器应该在每个应用程序启动/停止周期实例化一次,我怀疑IoC容器在这里没有任何用处。 从你的示例代码中可以看出,你需要一些控制器/操作过滤器来修改全局过滤器的行为...那么创建具有不同逻辑的基本过滤器和派生过滤器如何?
public abstract class BaseFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        //user some service locator to retrieve IService1, IService2

        //some logic based on RequestType
    }

    protected RequestType { get; set; }
}

public class SomeFilter : BaseFilter
{
    public SomeFilter(RequestType requestType)
    {
        RequestType = requestType;
    }
}

1
你可能需要了解 Ninject 对动作过滤器的支持: http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/ - FMM
谢谢提供链接,我之前不知道这个。所以我的回答实际上并不是一个答案... 但是我认为这个想法仍然可行 :) - ivan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接