.NET 5插件架构下动态加载程序集的AddHostedService注册问题
动态注册插件BackgroundService解决方案
问题根源
AddHostedService<T>() 是泛型扩展方法,要求泛型参数T为编译期即可确定的常量类型,你运行时扫描得到的moduleType是Type类型的运行时变量,不符合C#泛型语法要求,因此无法直接填入泛型尖括号。
解决方案1:直接注册服务(推荐,无需反射)
AddHostedService 本质是将服务实现作为单例注册到IHostedService服务集合,可直接手动注册绕过泛型限制:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { services.AddHostedService<MyInternalBackgroundServiceImplementation>(); TypeInfo[] moduleTypes = // 扫描目录查找dll、加载程序集并筛选得到符合要求的类型 foreach(var moduleType in moduleTypes) { // 先校验类型合法性 if (!typeof(IHostedService).IsAssignableFrom(moduleType)) { continue; } // 等价于原生AddHostedService的注册逻辑 services.AddSingleton(typeof(IHostedService), moduleType); } });
解决方案2:反射调用原生泛型方法
如果需要严格调用框架原生的AddHostedService方法,可以通过反射构造对应类型的泛型方法后调用:
using System.Reflection; using Microsoft.Extensions.DependencyInjection; public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { services.AddHostedService<MyInternalBackgroundServiceImplementation>(); // 提前获取AddHostedService的泛型方法定义 var addHostedServiceMethod = typeof(ServiceCollectionHostedServiceExtensions) .GetMethods(BindingFlags.Public | BindingFlags.Static) .First(m => m.Name == nameof(ServiceCollectionHostedServiceExtensions.AddHostedService) && m.GetParameters().Length == 1); TypeInfo[] moduleTypes = // 扫描目录查找dll、加载程序集并筛选得到符合要求的类型 foreach(var moduleType in moduleTypes) { if (!typeof(IHostedService).IsAssignableFrom(moduleType)) { continue; } // 构造针对当前类型的封闭泛型方法 var genericMethod = addHostedServiceMethod.MakeGenericMethod(moduleType); // 调用方法注册服务 genericMethod.Invoke(null, new object[] { services }); } });
注意事项
- 插件中
BackgroundService的所有构造函数依赖必须提前在主程序的服务容器中注册,否则实例化时会抛出依赖缺失异常 - 动态加载插件程序集时要保证主程序与插件依赖的
Microsoft.Extensions.Hosting.Abstractions版本一致,避免出现类型不匹配的问题 - 如果插件需要使用独立的依赖版本,建议使用
AssemblyLoadContext隔离加载上下文,避免版本冲突
内容的提问来源于stack exchange,提问作者monty
相关产品推荐
相关产品推荐

