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

.NET 10 ServiceCollection中为不同控制器配置不同IDataWriter实例

在.NET 10中为不同控制器配置不同的依赖链(共享中间服务)

可以通过.NET 10支持的**键控服务(Keyed Services)**来实现这个需求,无需在底层服务中添加额外参数,完全通过依赖注入配置来绑定不同的依赖链。以下是具体实现步骤:

1. 键控服务方案(推荐)

调整服务注册逻辑,为不同依赖链绑定专属标识,让DI容器自动匹配对应实例:

// 注册带键的IDataWriter实现,用"file"/"database"区分不同写入器
services.AddKeyedSingleton<IDataWriter, FileDataWriter>("file");
services.AddKeyedSingleton<IDataWriter, DatabaseDataWriter>("database");

// 注册带键的IAnonymiser,绑定对应键的IDataWriter
services.AddKeyedScoped<IAnonymiser, NameAnonymiser>("file", (sp, key) => 
    new NameAnonymiser(sp.GetRequiredKeyedService<IDataWriter>(key)));
services.AddKeyedScoped<IAnonymiser, NameAnonymiser>("database", (sp, key) => 
    new NameAnonymiser(sp.GetRequiredKeyedService<IDataWriter>(key)));

// 注册带键的IFormatter,绑定对应键的IAnonymiser
services.AddKeyedScoped<IFormatter, AddressFormatter>("file", (sp, key) => 
    new AddressFormatter(sp.GetRequiredKeyedService<IAnonymiser>(key)));
services.AddKeyedScoped<IFormatter, AddressFormatter>("database", (sp, key) => 
    new AddressFormatter(sp.GetRequiredKeyedService<IAnonymiser>(key)));

// 显式绑定控制器与对应键的IFormatter
services.AddScoped<CustomerFileController>(sp => 
    new CustomerFileController(sp.GetRequiredKeyedService<IFormatter>("file")));
services.AddScoped<CustomerDatabaseController>(sp => 
    new CustomerDatabaseController(sp.GetRequiredKeyedService<IFormatter>("database")));

方案说明

  • 键控服务:通过标识键区分不同的依赖分支,确保中间服务能绑定到对应链的IDataWriter。
  • Scoped生命周期:将IAnonymiser和IFormatter设为Scoped,保证每个请求创建新实例,避免单例服务无法动态切换依赖的问题。
  • 无侵入修改:底层服务(NameAnonymiser/AddressFormatter)无需任何改动,所有逻辑在DI配置层完成。

2. 替代方案:工厂模式

如果偏好不使用键控服务,可通过工厂模式实现依赖分支的切换:

  1. 定义工厂接口与实现:
public interface IFormatterFactory
{
    IFormatter GetFormatter(Type controllerType);
}

public class FormatterFactory : IFormatterFactory
{
    private readonly IServiceProvider _serviceProvider;

    public FormatterFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IFormatter GetFormatter(Type controllerType)
    {
        return controllerType switch
        {
            Type t when t == typeof(CustomerFileController) => 
                new AddressFormatter(new NameAnonymiser(_serviceProvider.GetRequiredService<FileDataWriter>())),
            Type t when t == typeof(CustomerDatabaseController) => 
                new AddressFormatter(new NameAnonymiser(_serviceProvider.GetRequiredService<DatabaseDataWriter>())),
            _ => throw new ArgumentOutOfRangeException(nameof(controllerType))
        };
    }
}
  1. 注册工厂与控制器:
services.AddSingleton<FileDataWriter>();
services.AddSingleton<DatabaseDataWriter>();
services.AddSingleton<IFormatterFactory, FormatterFactory>();

services.AddScoped<CustomerFileController>(sp => 
    new CustomerFileController(sp.GetRequiredService<IFormatterFactory>().GetFormatter(typeof(CustomerFileController))));
services.AddScoped<CustomerDatabaseController>(sp => 
    new CustomerDatabaseController(sp.GetRequiredService<IFormatterFactory>().GetFormatter(typeof(CustomerDatabaseController))));

关键注意事项

  • 禁止将IAnonymiser和IFormatter注册为Singleton:单例服务只会初始化一次,无法动态切换依赖的IDataWriter实例。
  • 完全符合需求:无需向底层服务传递任何标识参数,依赖切换逻辑完全由DI容器或工厂处理。

内容的提问来源于stack exchange,提问作者Sigurd Garshol

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 00:14:51