【问题标题】:IoC / DI with MVC Attributes具有 MVC 属性的 IoC / DI
【发布时间】:2011-12-05 04:01:25
【问题描述】:

我的一个 MVC 属性依赖于我希望通过构造函数注入的服务。显然 MVC 属性也需要一个无参数的构造函数。

    public MyAttribute()
    {
       ... 
    }

    public MyAttribute(IMyService)
    {
      ...
    }

我想我可以进行属性注入而不是构造函数注入,但是我的控制器(及其属性)位于一个单独的类库中,没有引用 IoC 容器。

是否可以在不引用 IoC 容器的情况下在属性过滤器中使用服务?

我将 Ninject 用于 MVC3 的价值

谢谢

【问题讨论】:

    标签: asp.net-mvc-3 ninject ioc-container


    【解决方案1】:

    作为一个通用解决方案(没有任何对您的 DI 框架的特殊集成支持),MVC3 向IDependencyResolver 询问IFilterProvider。换句话说,诀窍是:

    1. System.Web.Mvc.FilterProviders 集合中删除FilterAttributeFilterProvider
    2. 为您的特定 DI 框架注册 IDependencyResolver(如果您还没有这样做的话)。
    3. 在您的容器中注册一个自定义IFilterProvider,它可以注入任何请求属性的属性。

    看起来像这样:

    var container = new [your favorite container];
    
    // 1. Remove the FilterAttributeFilterProvider from the collection.
    var providers = FilterProviders.Providers
        .OfType<FilterAttributeFilterProvider>().ToList();
    
    providers.ForEach(p => FilterProviders.Providers.Remove(p));
    
    // 2. Register a IDependencyResolver
    DependencyResolver.SetResolver(new YourDiResolver(container));
    
    // 3. Register a customer IFilterProvider.
    container.Register<IFilterProvider, YourAttributeFilterProvider>();
    

    YourAttributeFilterProvider 将如下所示:

    private class YourAttributeFilterProvider
        : FilterAttributeFilterProvider
    {
        private readonly [your favorite container] container;
    
        public YourAttributeFilterProvider(
            [your favorite container] container)
            : base(false)
        {
            this.container = container;
        }
    
        public override IEnumerable<Filter> GetFilters(
            ControllerContext controllerContext, 
            ActionDescriptor actionDescriptor)
        {
            var filters = base.GetFilters(controllerContext,
                actionDescriptor).ToList();
    
            // Inject properties into attribute here.
            filters.ForEach(f => container.InjectProperties(f.Instance));
    
            return filters;
        }
    }
    

    许多框架,例如 Ninject 和 Autofac,都通过其 MVC 集成包对此提供了内置支持。了解如何手动执行此操作仍然很有价值。

    警告:

    关于 MVC 过滤器属性中的依赖注入的一个重要警告。 MVC caches attributes 并在应用程序域期间重用实例。这意味着它们实际上变成了单例,并且它们拖着它们的依赖关系。换句话说:这些依赖项也将成为单例,也称为captive dependency problem。 所以请确保您只将单例注入到您的属性中,因为如果您不这样做,您的生产系统将受到并发错误的困扰。

    尽管大多数 DI 框架都支持注入过滤器属性,但没有一个框架有助于解决这个问题。因此,更好的解决方案是让您的属性保持被动,如 herehere 所述。

    【讨论】:

    • 谢谢 Steven - 这很有帮助
    • +1 表示警告。如果您实现自己的IFilterProvider 并在调用actionDescriptor.ControllerDescriptor.GetFilterAttributes 以禁用缓存时传入false,则可以避免这种情况。
    • @TriQ 是正确的。 Autofac 和 Simple Injector 实际上使用该标志来禁用缓存。不幸的是,使用 Web API 你不能这样做;属性始终被缓存。
    【解决方案2】:

    几天前我也尝试过实现同样的目标。请阅读帖子here 有一个用于绑定过滤器的内置功能。

    【讨论】:

      猜你喜欢
      • 2015-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多