.NET Core如何注入同时为单例托管服务的IEnumerable<Interface>集合
问题根源
你第二种写法失效的核心原因:AddHostedService<T> 本质是将T作为IHostedService的实现注册到容器,多次注册不同服务类型时会生成独立实例,所以你注册的托管服务实例和IEnumerable<IConnectionListener>注入拿到的实例不是同一个,自然无法正常工作。
第一种手动new实例的方式虽然保证了实例唯一,但由于实例是你手动构造的,没有交给DI容器管理生命周期,容器默认不会自动调用其Dispose/DisposeAsync方法,存在资源泄漏风险。
正确实现方案
第一步:编写通用注册扩展方法
给IServiceCollection写扩展方法,一次注册就完成「单例实例+托管服务+接口暴露」三个动作,确保实例唯一且容器自动管理生命周期:
public static class ServiceCollectionExtensions { public static IServiceCollection AddHostedServiceAs<TService, TInterface>(this IServiceCollection services) where TService : class, TInterface, IHostedService where TInterface : class { // 先注册单例服务本身 services.AddSingleton<TService>(); // 作为IHostedService注册,复用上面的单例实例 services.AddHostedService(sp => sp.GetRequiredService<TService>()); // 作为目标接口注册,复用上面的单例实例 services.AddSingleton<TInterface>(sp => sp.GetRequiredService<TService>()); return services; } }
第二步:修正服务注册逻辑
直接用上面的扩展方法替换原来的注册代码即可,一行代码完成一个监听器的注册,容器自动处理生命周期、启停、注入逻辑:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureServices((hc, services) => { // 一行注册一个监听器,同时作为托管服务和IConnectionListener暴露 services.AddHostedServiceAs<ConnectionListener, IConnectionListener>(); services.AddHostedServiceAs<SslConnectionListener, IConnectionListener>(); // 注册Server托管服务 services.AddHostedService<Server>(); });
注意事项
你原代码里存在拼写错误:IConnectionListner少写了字母e,修正为IConnectionListener即可避免类型找不到的问题。按上述方案实现后,所有服务的构造、释放、启停都完全由DI容器托管,Server构造函数注入的IEnumerable<IConnectionListener就是正在运行的托管服务实例,事件绑定逻辑完全生效。
内容的提问来源于stack exchange,提问作者uriDium
相关产品推荐
相关产品推荐

