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

编程入门 行业动态 更新时间:2024-10-19 02:25:46
本文介绍了如何在 Asp.Net Core 中注册同一接口的多个实现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我有从同一个接口派生的服务.

I have services that are derived from the same interface.

public interface IService { } public class ServiceA : IService { } public class ServiceB : IService { } public class ServiceC : IService { }

通常,其他 IoC 容器(如 Unity)允许您通过一些区分它们的 Key 注册具体实现.

Typically, other IoC containers like Unity allow you to register concrete implementations by some Key that distinguishes them.

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

In ASP.NET Core, how do I register these services and resolve them at runtime based on some key?

我没有看到任何带有 key 或 name 参数的 Add 服务方法,这些参数通常用于区分具体的实施.

I don't see any Add Service methods that take a key or name parameter, which would typically be used to distinguish the concrete implementation.

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? } }

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

Is the Factory pattern the only option here?

更新 1我已经阅读了这里的文章,该文章展示了如何使用工厂模式获取服务当我们有多个具体实现时的实例.然而,它仍然不是一个完整的解决方案.当我调用 _serviceProvider.GetService() 方法时,我无法将数据注入到构造函数中.

Update1 I have gone though the article here that shows how to use the factory pattern to get service instances when we have multiple concrete implementations. However, it is still not a complete solution. When I call the _serviceProvider.GetService() method, I cannot inject data into the constructor.

例如考虑这个:

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,但是,这将要求我注入所有设置.我无法将特定的连接字符串注入服务.

How can _serviceProvider.GetService() inject the appropriate connection string? In Unity, or any other IoC library, we can do that at type registration. I can use IOption, however, that will require me to inject all settings. I cannot inject a particular connection string into the service.

另请注意,我试图避免使用其他容器(包括 Unity),因为那样我还必须使用新容器注册其他所有内容(例如控制器).

Also note that I am trying to avoid using other containers (including Unity) because then I have to register everything else (e.g., Controllers) with the new container as well.

此外,使用工厂模式创建服务实例不利于 DIP,因为它增加了客户端具有的依赖项数量详情.

Also, using the factory pattern to create service instances is against DIP, as it increases the number of dependencies a client has details here.

所以,我认为 ASP.NET Core 中的默认 DI 缺少两件事:

So, I think the default DI in ASP.NET Core is missing two things:

  • 使用密钥注册实例的能力
  • 能够在注册期间将静态数据注入构造函数
  • 推荐答案

    当我发现自己处于这种情况时,我使用 Func 做了一个简单的解决方法.

    I did a simple workaround using Func when I found myself in this situation.

    首先声明一个共享委托:

    Firstly declare a shared delegate:

    public delegate IService ServiceResolver(string key);

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

    Then in your Startup.cs, setup the multiple concrete registrations and a manual mapping of those types:

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

    并从任何向 DI 注册的类中使用它:

    And use it from any class registered with DI:

    public class Consumer { private readonly IService _aService; public Consumer(ServiceResolver serviceAccessor) { _aService = serviceAccessor("A"); } public void UseServiceA() { _aService.DoTheThing(); } }

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

    Keep in mind that in this example the key for resolution is a string, for the sake of simplicity and because OP was asking for this case in particular.

    但是您可以使用任何自定义分辨率类型作为键,因为您通常不希望一个巨大的 n-case 开关破坏您的代码.取决于您的应用的扩展方式.

    But you could use any custom resolution type as key, as you do not usually want a huge n-case switch rotting your code. Depends on how your app scales.

    更多推荐

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

    本文发布于:2023-11-14 04:21:10,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1586200.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:多个   接口   如何在   Net   Asp

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!