You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Generic Host如何禁止注册同一服务接口的多个实现?

解决.NET Generic Host中重复注册服务接口的问题

默认情况下,.NET Generic Host的DI容器允许同一服务接口(包括带相同键的键控服务)多次注册,最终获取时只会返回最后注册的实例。如果你想在构建Host时就检测到这类重复注册并抛出异常,不需要仅依赖单元测试,可以通过自定义服务注册验证逻辑实现。

实现步骤

  1. 编写扩展方法检查IServiceCollection,针对两种场景做重复校验:
    • 非键控服务:按ServiceType分组,同一接口注册多次则抛出异常
    • 键控服务:按ServiceType+ServiceKey的组合分组,同一接口+键的组合重复注册则抛出异常
  2. 在构建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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 23:03:10