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

.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 04:39:02