具有MVC属性的IoC/DI

Dav*_*gan 6 ninject ioc-container asp.net-mvc-3

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

    public MyAttribute()
    {
       ... 
    }

    public MyAttribute(IMyService)
    {
      ...
    }
Run Code Online (Sandbox Code Playgroud)

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

是否有方法在属性过滤器中使用服务而不引用IoC容器?

为了我的价值,我正在使用Ninject for MVC3

谢谢

Ste*_*ven 10

作为一般解决方案(没有任何对DI框架的特殊集成支持),MVC3要求IDependencyResolver提供IFilterProvider.换句话说,诀窍是:

  1. FilterAttributeFilterProviderSystem.Web.Mvc.FilterProviders集合中删除.
  2. 注册一个IDependencyResolver特定的DI框架(如果你还没有这样做).
  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>();
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

警告:

关于MVC过滤器属性中的依赖注入的一个重要警告.MVC缓存属性并在app域的持续时间内重用实例.这意味着他们几乎成为单身人士,他们拖着他们的依赖.换句话说:那些依赖关系也将成为单身人士,这也被称为圈养依赖问题.因此,请确保您只将单例注入您的属性,因为如果不这样做,您的生产系统将受到并发错误的困扰.

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


小智 1

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