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
相关产品推荐
相关产品推荐

