为什么这不是重复的
不要与“实际问题
自 .net 8 以来,微软似乎添加了拥有密钥服务的功能,这看起来很棒,但我注意到调用serviceProvider.GetServices(typeof(SomeInterface));
不会返回也具有密钥信息的实例。例如:
var collection = new ServiceCollection();
collection.AddKeyedSingleton<ITestInterface, TestClass1>("test1");
collection.AddKeyedSingleton<ITestInterface, TestClass2>("test2");
collection.AddSingleton<ITestInterface, TestClass3>();
var serviceProvider = collection.BuildServiceProvider();
var implementations = serviceProvider.GetServices<ITestInterface>();
Assert.NotNull(implementations);
Assert.NotEmpty(implementations);
// Expecting TestClass1, TestClass2, TestClass3
Assert.True(implementations.Count() == 3);
// Actually just TestClass3
我不确定上述测试的预期行为,我认为它应该通过并返回给定类型的所有绑定。那么就提出了如何从serviceProvider
获得预期结果的问题。我想也许我需要使用
serviceProvider.GetKeyedServices<ITestInterface>()
,但不幸的是,这需要您提供一个密钥,在这种情况下,我们想忽略密钥并只获取给定类型的所有实现。那么任何人都可以建议如何获得预期的行为吗?即使它需要两个服务提供商方法之间的联合。
虽然
我的这个答案解释了如何将所有密钥注册解析为IDictionary<TKey, TService>
,但这并不能让您获得您希望看到的行为。但是,可以使用自定义扩展方法来实现此行为:
public static void AddBothKeyedAndDefaultSingleton<TService, TImplementation>(
IServiceCollection services, string key)
where TService : class
where TImplementation : class, TService
{
services.AddKeyedSingleton<TService, TImplementation>(key);
services.AddSingleton(sp => sp.GetRequiredKeyedService<TService>(key));
}
如果您使用此扩展方法运行测试,您将获得预期的输出:
var collection = new ServiceCollection();
collection.AddBothKeyedAndDefaultSingleton<ITestInterface, TestClass1>("test1");
collection.AddBothKeyedAndDefaultSingleton<ITestInterface, TestClass2>("test2");
collection.AddSingleton<ITestInterface, TestClass3>();
var serviceProvider = collection.BuildServiceProvider();
var implementations = serviceProvider.GetServices<ITestInterface>();
Assert.True(implementations.Count() == 3);
您可能会想迭代整个 IServiceCollection
并为每个键控注册添加额外的注册,从而使其成为全局行为更改,但这将是一个严重的错误。您正在使用的其他可重用库和框架组件(或将来要安装的更新)很可能取决于当前的行为。
var implementations = serviceProvider.GetKeyedServices<ITestInterface>(KeyedService.AnyKey);
此方法存在一个错误,已在 .NET 9 中修复。因此请确保至少升级到 .NET 9 或获取相应的 v9.0.0 NuGet 包 (Microsoft.Extensions.DependencyInjection.Abstractions
)。