使用Autofac将接口的不同实现注入到不同的控制器中

时间:2014-07-14 07:45:18

标签: c# asp.net-mvc autofac

我有一个IFileSystemService界面,它定义了一组文件&目录管理功能。它有一个实现,并由Autofac注入需要它的控制器。

但是,由于我们无法控制的原因,我们现在要求将网站的一个特定部分移动到使用数据库而不是文件系统,同时保持相同的功能(即" lite"使用数据库进行存储的文件系统版本)。为此,我创建了IFileSystemService的第二个实现,它与DB一起使用而不是实际的文件系统。

但是,我无法弄清楚如何告诉Autofac在需要它的特定控制器上使用第二个实现,同时将原始实现保留为所有其他实现的默认实现。

1 个答案:

答案 0 :(得分:1)

服务可以被命名为#34;在AutoFac中按https://code.google.com/p/autofac/wiki/TypedNamedAndKeyedServices

IFileSystemService的Db实现注册为命名实例:

builder.Register<MyDbFileSystemService>().Named<IFileSystemService>("DbFileSystemService");

然后让依赖控制器使用命名注册:

builder.Register(c => new MyControllerWithDbDependency(c.Resolve< IFileSystemService >("DbFileSystemService"))) .As<Controller>() .etc

如果更新的问题由于大量额外依赖项而无法实现,我会执行以下操作之一:

  1. 将IFileSystemService依赖项移动到控制器的属性
  2. 将IFileSystemService的解析引入工厂并在运行时动态解析依赖关系
  3. 将具体的IFileSystemService实现注册为自己特定类型的服务,然后在控制器构造函数的签名中使用特定实现
  4. IFileSystemService Factory

    public class MyControllerWithDbDependency : Controller
    {
       MyControllerWithDbDependency(IFileSystemServiceFactory fileSystemServiceFactory,
                                    ISomeOtherDependency ...)
       {
          _service = fileSystemServiceFactory.Create("MyDbFileSystemServiceFactory");
       }
    }
    
    public interface IFileSystemServiceFactory
    {
        IFileSystemServiceFactory Create(string dependencyName);
    }
    
    public class AutoFacFileSystemServiceFactory : IFileSystemService
    {
        private readonly IComponentContext _componentContext;
    
        public AutoFacFileSystemServiceFactory(IComponentContext componentContext)
        {
            if (componentContext == null) throw new ArgumentNullException("componentContext");
            _componentContext = componentContext;
        }
    
        public IFileSystemService Create(string dependencyName)
        {
            return _componentContext.ResolveNamed<IFileSystemService>(dependencyName);
        }
    }
    

    即。每个控制器负责指定它所需的特定IFileSystemService依赖关系,这反过来意味着不会更改控制器的AutoFac配置。

    老实说,我通常只在需要解决的特定类型直到运行时才知道的情况下使用这种技术 - 不像在问题中它将用作解决方法。

    显然,如果你有大量的控制器和一小组IFileSystemService实现,并且从设计的角度来看它是有意义的,你可以将工厂的Create调用推送到自定义控制器基类型,并保存自己一些代码重复。

    将IFileSystemService的特定实现注册为自己的服务

    public class MyControllerWithDbDependency : Controller
    {
       MyControllerWithDbDependency(MyDbFileSystemService dbFileSystemService,
                                    ISomeOtherDependency ...)
       {
          // ...
       }
    }
    
    // AutoFac configuration
    builder.RegisterType<MyDbFileSystemService>()
       .As<MyDbFileSystemService>()
       .InstancePerWhatever();
    builder.RegisterType<DefaultFileSystemService>()
       .As<IFileSystemService>()
       .InstancePerWhatever();