.NET Generic Host如何禁止注册同一服务接口的多个实现?
解决.NET Generic Host中重复注册服务接口的问题
默认情况下,.NET Generic Host的DI容器允许同一服务接口(包括带相同键的键控服务)多次注册,最终获取时只会返回最后注册的实例。如果你想在构建Host时就检测到这类重复注册并抛出异常,不需要仅依赖单元测试,可以通过自定义服务注册验证逻辑实现。
实现步骤
- 编写扩展方法检查
IServiceCollection,针对两种场景做重复校验:- 非键控服务:按
ServiceType分组,同一接口注册多次则抛出异常 - 键控服务:按
ServiceType+ServiceKey的组合分组,同一接口+键的组合重复注册则抛出异常
- 非键控服务:按
- 在构建Host之前调用该验证方法,确保重复注册在Host启动前被拦截。
示例代码
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; using System.Linq; using System.Threading.Tasks; namespace IHostTest; internal class Program { static async Task Main() { var hostBuilder = Host.CreateDefaultBuilder().ConfigureServices(services => { services.AddSingleton<ISomeService, SomeService1>(); // 取消注释下面这行会触发异常:ISomeService已重复注册 // services.AddSingleton<ISomeService, SomeService2>(); services.AddKeyedSingleton<ISomeService, SomeService1>("key"); // 取消注释下面这行会触发异常:ISomeService+key组合已重复注册 // services.AddKeyedSingleton<ISomeService, SomeService2>("key"); // 执行重复注册验证 services.ValidateNoDuplicateServices(); }); var host = hostBuilder.Build(); var service = host.Services.GetRequiredService<ISomeService>(); var keyedService = host.Services.GetRequiredKeyedService<ISomeService>("key"); await host.RunAsync(); } } // 扩展方法实现 public static class ServiceCollectionExtensions { public static void ValidateNoDuplicateServices(this IServiceCollection services) { // 校验非键控服务重复 var nonKeyedDuplicates = services .Where(sd => sd.ServiceKey == null) .GroupBy(sd => sd.ServiceType) .Where(g => g.Count() > 1) .Select(g => g.Key.Name) .ToList(); if (nonKeyedDuplicates.Any()) { throw new InvalidOperationException($"检测到重复注册的服务接口:{string.Join(", ", nonKeyedDuplicates)}"); } // 校验键控服务重复 var keyedDuplicates = services .Where(sd => sd.ServiceKey != null) .GroupBy(sd => new { sd.ServiceType.Name, sd.ServiceKey }) .Where(g => g.Count() > 1) .Select(g => $"{g.Key.Name} (键: {g.Key.ServiceKey})") .ToList(); if (keyedDuplicates.Any()) { throw new InvalidOperationException($"检测到重复注册的带键服务:{string.Join(", ", keyedDuplicates)}"); } } } internal interface ISomeService { } internal class SomeService1 : ISomeService { } internal class SomeService2 : ISomeService { }
说明
- 验证逻辑会在
ConfigureServices阶段执行,一旦检测到重复注册,立即抛出InvalidOperationException,阻止Host继续构建。 - 你可以根据业务需求调整校验规则,比如允许特定接口重复注册,或者自定义异常提示内容。
内容的提问来源于stack exchange,提问作者bairog
相关产品推荐
相关产品推荐

