如何在Asp.Net Core中注册同一个接口的多个实现?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (92)

我有从相同的接口派生的服务

public interface IService
{
}

public class ServiceA : IService
{
}

public class ServiceB : IService
{    
}

public class ServiceC : IService
{    
}

通常,其他IOC容器Unity允许您通过某些Key区分它们的具体实现来注册。

在Asp.Net Core中,我如何注册这些服务并在运行时根据某个键来解决它?

我没有看到任何通常用于区分具体实现的AddService方法参数keyname参数。

    public void ConfigureServices(IServiceCollection services)
    {            
         // How do I register services here of the same interface            
    }


    public MyController:Controller
    {
       public void DoSomeThing(string key)
       { 
          // How do get service based on key
       }
    }

工厂模式是唯一的选择吗? 我已经去了这里的文章它展示了当我们有多个concreate实现时,如何使用工厂模式来获取服务实例。但它仍然不是完整的解决方案。当我调用_serviceProvider.GetService()方法时,我无法将数据注入到构造函数中。例如考虑这个例子

public class ServiceA : IService
{
     private string _efConnectionString;
     ServiceA(string efconnectionString)
     {
       _efConnecttionString = efConnectionString;
     } 
}

public class ServiceB : IService
{    
   private string _mongoConnectionString;
   public ServiceB(string mongoConnectionString)
   {
      _mongoConnectionString = mongoConnectionString;
   }
}

public class ServiceC : IService
{    
    private string _someOtherConnectionString
    public ServiceC(string someOtherConnectionString)
    {
      _someOtherConnectionString = someOtherConnectionString;
    }
}

如何_serviceProvider.GetService()注入适当的连接字符串?在Unity或任何其他IOC中,我们可以在注册时进行此操作。我可以使用IOption,但是这将需要我注入所有设置,我不能在服务中注入特定的连接字符串

另外请注意,我正试图避免使用其他容器(包括Unity),因为那样我必须在其他容器(例如控制器)中注册新的容器。

同样使用工厂模式来创建服务实例是违反DIP的,因为工厂增加了依赖关系的数量,客户端被强制依赖 细节

所以我认为ASP.NET核心中的默认DI缺少两件事 1>使用密钥 2 注册实例>在注册期间将静态数据注入构造函数

提问于
用户回答回答于

Func当我遇到这种情况时,我做了一个简单的解决方法。

services.AddTransient<ServiceA>();
services.AddTransient<ServiceB>();
services.AddTransient<ServiceC>();

services.AddTransient(factory =>
{
    Func<string, IService> accesor = key =>
    {
        switch(key)
        {
            case "A":
                return factory.GetService<ServiceA>();
            case "B":
                return factory.GetService<ServiceB>();
            case "C":
                return factory.GetService<ServiceC>();
            default:
                throw new KeyNotFoundException(); // or maybe return null, up to you
         }
    };
    return accesor;
});

并且从任何在DI注册的课程中使用它,例如:

public class Consumer
{
    private readonly Func<string, IService> _serviceAccessor;

    public Consumer(Func<string, IService> serviceAccessor)
    {
        _serviceAccessor = serviceAccesor;
    }

    public void UseServiceA()
    {
        serviceAccessor("A").DoIServiceOperation();
    }
}
用户回答回答于

另一种选择是使用扩展方法GetServicesMicrosoft.Extensions.DependencyInjection

将服务注册为:

services.AddSingleton<IService, ServiceA>();
services.AddSingleton<IService, ServiceB>();
services.AddSingleton<IService, ServiceC>();

然后用一点Linq解决:

var services = serviceProvider.GetServices<IService>();
var serviceB = services.First(o => o.GetType() == typeof(ServiceB));

要么

var serviceZ = services.First(o => o.Name.Equals("Z"));

(假设IService有一个名为“Name”的字符串属性)

确保有 using Microsoft.Extensions.DependencyInjection;

扫码关注云+社区