如何从 IServiceCollection 获取相同服务的不同实例
How to get different instances of same service from IServiceCollection
我有一个 Bar class 定义为这个
public class Bar: IBar
{
private readonly IFoo _foo;
private readonly string _keyname;
public Bar(IFoo, string keyName)
{
//assign class field
}
}
keyname字符串区分Bar的对象。 Bar 的方法使用此键名从 class.
外部获取不同的 settings/config
我希望 class 的客户端在单个 class 中具有不同的 Bar 实例。如果我们不使用服务,客户端可以做这样的事情
var bar1 = new Bar(foo, "key1");//instantiate with new
var bar2 = new Bar(foo, "key2");
为了注册 Bar class,我创建了一个这样的扩展方法
public static IServiceCollection AddMyService(this IServiceCollection services, string keyName)
{
services.AddSingleton<IFoo, Foo>();
services.AddTransient<IBar>(sp =>
ActivatorUtilities.CreateInstance<Bar>(sp, keyName)
);
return services;
}
我想让客户端像这样注册多个实例
services.AddMyService("key1");
services.AddMyService("key2");
但我不确定他们将如何通过依赖注入访问 class 中的两个注册服务。这是解决这个问题的正确方法吗?
开箱即用的 dotnet 核心依赖注入不允许使用命名服务。
在您的情况下,您可以做的最简单的事情是注册所有 Bar 服务,然后将它们作为 IEnumerable 注入:
var factory = ActivationUtilities.CreateFactory(typeof(Bar), new Type[] { typeof(string) });
services.AddSingleton<IFoo, Foo>();
services.AddTransient<IBar>(sp =>
(IBar) factory(sp, new object[] { "key1" })
);
services.AddTransient<IBar>(sp =>
(IBar) factory(sp, new object[] { "key2" })
);
services.AddTransient<AClient>();
public class AClient {
private IEnumerable<IBar> _bars;
public AClient(IEnumerable<IBar> bars)
{
_bars = bars
}
public IBar GetBarByKey(string key) => _bars.FirstOrDefault(x => x.Key == key);
}
ActivationUtilities.CreateFactory 方法 returns ObjectFactory 委托的一个对象,它表示一个函数,该函数接受 IServiceProvider 和参数列表的输入。通过这种方式,您可以创建对象,从服务提供者那里获取一些构造参数,而一些参数是直接给出的。
您可以通过注入一个为给定键创建 IBar
的工厂来解决此问题:
public interface IBarFactory { IBar Create(string key); }
public class BarFactory : IBarFactory {
private readonly IFoo _foo;
public BarFactory(IFoo foo) => _foo = foo;
public IBar Create(string key) => new Bar(_foo, key);
}
客户端代码可以注入这个工厂:
public class Client1 {
private readonly IBar _bar1;
public Client1(IBarFactory barFactory)
=> _bar1 = barFactory.Create("key1");
}
注意BarFactory
需要注入并转发Bar
的所有依赖。
只有 IBarFactory
需要在您的 DI 容器中注册。不同的 IBar
不需要注册(当然,除了像 IFoo
这样的依赖项)。
一个缺点是当你想在 Client1
的单元测试中模拟 IBar
时需要额外的设置。您必须模拟并设置 IBarFactory
到 return 模拟 IBar
.
我有一个 Bar class 定义为这个
public class Bar: IBar
{
private readonly IFoo _foo;
private readonly string _keyname;
public Bar(IFoo, string keyName)
{
//assign class field
}
}
keyname字符串区分Bar的对象。 Bar 的方法使用此键名从 class.
外部获取不同的 settings/config我希望 class 的客户端在单个 class 中具有不同的 Bar 实例。如果我们不使用服务,客户端可以做这样的事情
var bar1 = new Bar(foo, "key1");//instantiate with new
var bar2 = new Bar(foo, "key2");
为了注册 Bar class,我创建了一个这样的扩展方法
public static IServiceCollection AddMyService(this IServiceCollection services, string keyName)
{
services.AddSingleton<IFoo, Foo>();
services.AddTransient<IBar>(sp =>
ActivatorUtilities.CreateInstance<Bar>(sp, keyName)
);
return services;
}
我想让客户端像这样注册多个实例
services.AddMyService("key1");
services.AddMyService("key2");
但我不确定他们将如何通过依赖注入访问 class 中的两个注册服务。这是解决这个问题的正确方法吗?
开箱即用的 dotnet 核心依赖注入不允许使用命名服务。
在您的情况下,您可以做的最简单的事情是注册所有 Bar 服务,然后将它们作为 IEnumerable 注入:
var factory = ActivationUtilities.CreateFactory(typeof(Bar), new Type[] { typeof(string) });
services.AddSingleton<IFoo, Foo>();
services.AddTransient<IBar>(sp =>
(IBar) factory(sp, new object[] { "key1" })
);
services.AddTransient<IBar>(sp =>
(IBar) factory(sp, new object[] { "key2" })
);
services.AddTransient<AClient>();
public class AClient {
private IEnumerable<IBar> _bars;
public AClient(IEnumerable<IBar> bars)
{
_bars = bars
}
public IBar GetBarByKey(string key) => _bars.FirstOrDefault(x => x.Key == key);
}
ActivationUtilities.CreateFactory 方法 returns ObjectFactory 委托的一个对象,它表示一个函数,该函数接受 IServiceProvider 和参数列表的输入。通过这种方式,您可以创建对象,从服务提供者那里获取一些构造参数,而一些参数是直接给出的。
您可以通过注入一个为给定键创建 IBar
的工厂来解决此问题:
public interface IBarFactory { IBar Create(string key); }
public class BarFactory : IBarFactory {
private readonly IFoo _foo;
public BarFactory(IFoo foo) => _foo = foo;
public IBar Create(string key) => new Bar(_foo, key);
}
客户端代码可以注入这个工厂:
public class Client1 {
private readonly IBar _bar1;
public Client1(IBarFactory barFactory)
=> _bar1 = barFactory.Create("key1");
}
注意BarFactory
需要注入并转发Bar
的所有依赖。
只有 IBarFactory
需要在您的 DI 容器中注册。不同的 IBar
不需要注册(当然,除了像 IFoo
这样的依赖项)。
一个缺点是当你想在 Client1
的单元测试中模拟 IBar
时需要额外的设置。您必须模拟并设置 IBarFactory
到 return 模拟 IBar
.