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

ASP.NET Core Web应用多实现依赖注入:如何枚举注册服务?

问题描述

我正在开发一个类似OpenLM的解决方案,希望通过配置文件定义输入(示例配置如下):

"Collectors": {
  "Frequency": "2",
  "FlexLM": {
    "ExePath": "Resources\\lmutil.exe",
    "Servers": [
      {
        "Server": "port@server",
        "Product": "product"
      }
    ]
  },
  "SentinelRMS": {
    "ExePath": "Resources\\lsmon.exe",
    "Servers": [
      {
        "Server": "server",
        "Product": "product 2"
      }
    ]
  }
}

该场景需要两个分别与FlexLM、Sentinel RMS通信的服务,我已通过非IoC方式实现服务构建与并行消费(代码如下):

internal static IEnumerable<IDataCollector> Build()
{
    var time = DateTime.Now;
    var collectors = new List<IDataCollector>();
    AddSection("Collectors:FlexLM", collectors);
    AddSection("Collectors:SentinelRMS", collectors);
    return collectors;
}

private static void AddSection(string section, List<IDataCollector> collectors)
{
   if (ConfigurationAdapter.Sections.Contains(section))
   {
        var exePath = ConfigurationAdapter.Config.GetSection($"{section}:ExePath").Get<string>();

        var children = ConfigurationAdapter.Config.GetSection(section + ":Servers").Get<ServerConfig[]>();
        if (children != null)
        {
            foreach (var item in children)
            {
               if (section == "Collectors:FlexLM")
               {
                   collectors.Add(new FlexLmDataCollector(item.Server, item.Product, exePath));
               }
               else if (section == "Collectors:SentinelRMS")
               {
                   collectors.Add(new SentinelRmsDataCollector(item.Server, item.Product, exePath));
               }
            }
        }
    }
}

后续并行消费服务的代码:

Parallel.ForEach(collectors, new ParallelOptions { MaxDegreeOfParallelism = 99 }, (collector) =>
{
    collector.ReadLicenses();
});

请问如何在ASP.NET Core中以枚举方式将这些服务注册到依赖注入容器中?


解决方案

1. 定义收集器类型枚举

创建枚举替代硬编码字符串,统一标识收集器类型:

public enum CollectorType
{
    FlexLM,
    SentinelRMS
}

2. 重构配置绑定模型

创建强类型配置类,简化配置读取逻辑:

// 单个服务器配置
public class ServerConfig
{
    public string Server { get; set; }
    public string Product { get; set; }
}

// 单类收集器的配置集合
public class CollectorConfig
{
    public string ExePath { get; set; }
    public List<ServerConfig> Servers { get; set; } = new List<ServerConfig>();
}

// 根配置类
public class CollectorsRootConfig
{
    public int Frequency { get; set; }
    public Dictionary<CollectorType, CollectorConfig> Collectors { get; set; } = new Dictionary<CollectorType, CollectorConfig>();
}

3. 编写DI扩展注册方法

创建扩展方法,从配置中解析并注册所有IDataCollector实例:

public static class DataCollectorServiceExtensions
{
    public static IServiceCollection AddDataCollectors(this IServiceCollection services, IConfiguration configuration)
    {
        var rootConfig = configuration.GetSection("Collectors").Get<CollectorsRootConfig>();
        if (rootConfig == null) return services;

        foreach (var (collectorType, config) in rootConfig.Collectors)
        {
            foreach (var server in config.Servers)
            {
                // 根据枚举类型创建对应收集器实例
                IDataCollector collector = collectorType switch
                {
                    CollectorType.FlexLM => new FlexLmDataCollector(server.Server, server.Product, config.ExePath),
                    CollectorType.SentinelRMS => new SentinelRmsDataCollector(server.Server, server.Product, config.ExePath),
                    _ => throw new NotSupportedException($"不支持的收集器类型:{collectorType}")
                };

                // 注册为瞬态服务(可根据实际需求调整生命周期为Singleton/Scoped)
                services.AddTransient<IDataCollector>(_ => collector);
            }
        }

        return services;
    }
}

4. 在启动类中注册服务

在Program.cs中调用扩展方法完成服务注册:

var builder = WebApplication.CreateBuilder(args);

// 注册数据收集器服务
builder.Services.AddDataCollectors(builder.Configuration);

// 其他服务注册逻辑...

var app = builder.Build();

// 中间件配置...

app.Run();

5. 注入并使用收集器

在需要执行收集逻辑的类中,通过构造函数注入IEnumerable<IDataCollector>获取所有实例:

public class LicenseMonitoringService
{
    private readonly IEnumerable<IDataCollector> _collectors;

    public LicenseMonitoringService(IEnumerable<IDataCollector> collectors)
    {
        _collectors = collectors;
    }

    public void ExecuteCollection()
    {
        Parallel.ForEach(_collectors, new ParallelOptions { MaxDegreeOfParallelism = 99 }, collector =>
        {
            collector.ReadLicenses();
        });
    }
}

优化建议

  • 若收集器实例可复用且线程安全,可将注册生命周期改为Singleton
  • 添加配置验证逻辑,确保ExePath、Server等必填字段不为空
  • 后续新增收集器类型时,只需扩展CollectorType枚举和switch分支即可,无需修改其他注册逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 17:05:28