关于 MVC 3 中 Ninject 创建的动作过滤器的生命周期问题

发布于 2024-12-04 15:54:29 字数 1724 浏览 0 评论 0原文

我想在我的 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,这里的 BindFilter 语法似乎不必要地冗长,我不确定它是否按照我的预期工作,似乎会有更好的方法如果控制器或操作方法上不存在 RequestTypeAttribute,则将默认的 RequestType 注入到操作过滤器中。

请赐教!

I would like to use a global-scoped action filter in my MVC 3 application using Ninject; however, I'm trying to understand the lifetime of that filter, its dependencies, and how to introduce variations to its dependencies by decorating my controllers and/or action methods.

I'd like to have my filter type depend on objects whose lifetimes are bound to request scope, so, something like this:

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

    // IActionFilter implementation here...
}

... and in the module config ...

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)

And an attribute on controllers and/or action methods to represent an application-specific "request type":

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

Am I understanding properly how this should work? Will a new instance of MyGlobalActionFilter get spun up and injected on each HTTP request? If this won't work, what am I missing, and what would be a better way to make this work?

Also, with injecting the RequestType, the BindFilter syntax here seems unnecessarily verbose, I'm not sure if it works like I expect, and it seems there would be a better way to inject a default RequestType into the action filter if a RequestTypeAttribute isn't present on the controller or the action method.

Please enlighten me!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

素食主义者 2024-12-11 15:54:30

我还没有看到 Microsoft 的官方文档 IFilterProvider 被准确调用的时间和频率。但根据我的观察,似乎每个请求都会调用一次。这意味着瞬态绑定过滤器基本上是 InRequestScope 绑定的,区别在于它们不会在请求结束时由 Ninject 处理。

您应该做一些更改:

  • 不要从 ActionFilterAttribute 派生,而是实现 IActionFilter
    而是为了防止它被意外地用作属性。
  • 重新考虑对所有绑定使用 FilterScope.Global。我考虑一下
    在运行的操作/控制器上设置过滤器是不好的做法
    全球优先。

另请注意,将为每个匹配绑定创建并执行一个过滤器。这意味着当前带有 RequestType.Undefined 的请求会在每个请求上运行,无论操作或控制器上是否有属性。此外,如果操作和控制器上有属性,则执行它们。

I havn't seen an official documentation from Microsoft when and how often IFilterProvider is called exactly. But from my observations it seems to be called once for each request. This means that transient bound filters are basically InRequestScope bound with the difference that they aren't disposed by Ninject at the end of the request.

There are some changes you should do:

  • Do not derive from ActionFilterAttribute but implement IActionFilter
    instead to prevent that it is accidentially used as attribute.
  • Rethink the use of FilterScope.Global for all bindings. I consider it
    as bad practice to have filters on actions/controllers running with
    global priority.

Also be aware that a filter for each matching binding is created and executed. This means that currently the one with RequestType.Undefined is run on every request independent of whether there is an attribute on the action or controller. Additionally, the ones for action and controllers are executed if there is a attribute on them.

枫林﹌晚霞¤ 2024-12-11 15:54:30

如果“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;
    }
}

if "System.Web.Mvc.GlobalFilters.Filters" is what you mean by "global-scoped action filter", then those filters are supposed to be instantiated once per application start/stop cycle and i doubt IoC container can be of any use here.
as i can see from your sample code you need some controller/action filters to modify beavior of global filters... what about creating base filter and derived filters with varying logic?

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文