首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在Asp.Net内核中注册同一接口的多个实现?

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

Stack Overflow用户
提问于 2016-08-27 05:42:10
回答 26查看 261.3K关注 0票数 405

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

代码语言:javascript
复制
public interface IService { }
public class ServiceA : IService { }
public class ServiceB : IService { } 
public class ServiceC : IService { }

通常,其他IoC容器,如Unity允许您通过以下方式注册具体的实现Key这就是他们的不同之处。

在ASP.NET核心中,如何注册这些服务,并在运行时根据某个键解析它们?

我什么也没看到Add服务方法需要key或者name参数,该参数通常用于区分具体的实现。

代码语言:javascript
复制
public void ConfigureServices(IServiceCollection services)
    {            
         // How do I register services of the same interface?            
    }


    public MyController:Controller
    {
       public void DoSomething(string key)
       { 
          // How do I resolve the service by key?
       }
    }

工厂模式是这里唯一的选择吗?

Update1

我已经把这篇文章看了一遍。here这说明了当我们有多个具体实现时,如何使用工厂模式来获取服务实例。然而,它仍然不是一个完整的解决方案。当我调用_serviceProvider.GetService()方法时,我无法将数据注入到构造函数中。

例如,考虑以下内容:

代码语言:javascript
复制
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背道而驰,因为它增加了客户端具有的依赖项的数量

详细信息here](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=100) [..。因此,我认为ASP.NET核心中的默认DI缺少两个东西:

  1. 使用密钥注册实例的能力
  2. 在注册期间将静态数据注入构造函数的能力
EN

回答 26

Stack Overflow用户

回答已采纳

发布于 2017-05-25 18:14:32

我做了一个简单的变通方法Func当我发现自己处于这种境地的时候。

首先声明一个共享委托:

代码语言:js
复制
public delegate IService ServiceResolver(string key);

然后在你的Startup.cs,设置多个具体注册和这些类型的手动映射:

代码语言:javascript
复制
services.AddTransient();
services.AddTransient();
services.AddTransient();

services.AddTransient(serviceProvider => key =>
{
    switch (key)
    {
        case "A":
            return serviceProvider.GetService();
        case "B":
            return serviceProvider.GetService();
        case "C":
            return serviceProvider.GetService();
        default:
            throw new KeyNotFoundException(); // or maybe return null, up to you
    }
});

并在任何注册了DI的类中使用它:

代码语言:javascript
复制
public class Consumer
{
    private readonly IService _aService;

    public Consumer(ServiceResolver serviceAccessor)
    {
        _aService = serviceAccessor("A");
    }

    public void UseServiceA()
    {
        _aService.DoTheThing();
    }
}

请记住,在本例中,解析的关键字是一个字符串,这是为了简单起见,因为OP特别要求这种情况。

但是你可以使用任何自定义的解析类型作为键,因为你通常不想要一个巨大的n-case开关来腐烂你的代码。这取决于你的应用程序的伸缩性。

票数 365
EN

Stack Overflow用户

发布于 2017-07-04 02:22:54

另一种选择是使用扩展方法`GetServices`来自Microsoft.Extensions.DependencyInjection..。

将您的服务注册为:

代码语言:javascript
复制
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();

然后用一点Linq来解决:

代码语言:javascript
复制
var services = serviceProvider.GetServices();
var serviceB = services.First(o => o.GetType() == typeof(ServiceB));

或者

代码语言:js
复制
var serviceZ = services.First(o => o.Name.Equals("Z"));

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

一定要有using Microsoft.Extensions.DependencyInjection;

更新

AspNet 2.1来源:`GetServices`

票数 130
EN

Stack Overflow用户

发布于 2018-01-23 02:09:49

工厂方法当然是可行的。另一种方法是使用继承来创建从IService继承的各个接口,在IService实现中实现继承的接口,并注册继承的接口而不是基接口。添加继承层次结构或工厂是否是“正确的”模式完全取决于您与谁交谈。当在使用泛型的同一应用程序中处理多个数据库提供程序时,我经常需要使用此模式,例如IRepository,作为数据访问的基础。

示例接口和实现:

代码语言:javascript
复制
public interface IService 
{
}

public interface IServiceA: IService
{}

public interface IServiceB: IService
{}

public IServiceC: IService
{}

public class ServiceA: IServiceA 
{}

public class ServiceB: IServiceB
{}

public class ServiceC: IServiceC
{}

容器:

代码语言:javascript
复制
container.Register();
container.Register();
container.Register();
票数 52
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39174989

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档