咨询区
LP13
我有三个 Service
类实现了同一个接口,参考代码如下:
public interface IService { }
public class ServiceA : IService { }
public class ServiceB : IService { }
public class ServiceC : IService { }
我知道像其他的 DI 容器,比如 Unity 是在注册实现类的时候通过不同的key来区分,在 ASP.NET Core
中做 AddService 时并没有看到 key
或 name
参数的重载方法。
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?
}
}
请问我该如何实现呢?
回答区
Miguel A. Arilla
我也遇到了这种场景,不过我是用 Func
做了一个折中方案。
首先:定义一个 委托
。
public delegate IService ServiceResolver(string key);
然后:在 Startup.cs
中做多个实现类注册。
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
}
});
后期:如果想使用的话,通过 key
从 Func 中提取具体的实例,参考代码如下:
public class Consumer
{
private readonly IService _aService;
public Consumer(ServiceResolver serviceAccessor)
{
_aService = serviceAccessor("A");
}
public void UseServiceA()
{
_aService.DoTheThing();
}
}
为了做演示目的,我这里只用了 string 作为解析,你可以根据自己的场景具体实现。
点评区
在 Asp.Net Core
中是不支持这种多注册的,这就有点尴尬了,Miguel A. Arilla
大佬提供的方案不错,学习了。