运行中C#应用能否通过DI容器更新服务实现并递归重建依赖?
在运行中C#应用通过DI部署新代码的可行性与实现方案
一、理论可行性
你的设想理论上是可行的,但需要解决几个核心技术问题:
- 运行时代码加载:必须将新的
Service实现编译为独立程序集(如.dll文件),通过Assembly.LoadFrom或Assembly.LoadFile在运行时动态加载。原有项目内的静态类无法直接替换,必须依赖外部编译的独立程序集。 - DI容器的动态更新:.NET内置DI容器(
IServiceCollection/ServiceProvider)是不可变的——一旦构建ServiceProvider,就无法修改已注册的服务。要实现递归更新依赖,要么使用支持动态注册/替换的第三方DI容器,要么自行封装容器管理逻辑。 - 状态保留:要保留服务原有属性,需手动迁移状态——比如先获取旧服务实例,将需要保留的属性值复制到新实例中。这要求服务设计时预先考虑状态可迁移,或提供统一的状态导出/导入接口。
你设想的IServiceCollection.UpdateRecursively<IService, Service>()方法,核心逻辑应该是:
- 从DI容器中移除原
IService的注册 - 注册新的
Service实现 - 递归查找所有依赖
IService的已注册服务,销毁旧实例并重新创建新实例(同时迁移状态) - 对新创建的服务,继续递归处理其依赖链
二、现成实现
目前有成熟方案可实现类似需求:
- 第三方DI容器:Autofac支持动态注册和组件替换,可通过
ContainerBuilder重新构建容器并更新,结合生命周期管理实现依赖的递归重建;StructureMap也具备类似动态更新能力。 - 插件框架:MEF(Managed Extensibility Framework)专为动态加载插件设计,支持运行时添加/替换导出服务,自动处理依赖关系。
- 自定义封装:基于.NET内置DI,自行封装
DynamicServiceProvider,维护可变更的服务注册集合,在更新时重新构建服务实例链并处理状态迁移。
三、在启动类外部访问DI容器
通常有两种合规方式:
- 全局静态引用:启动时将构建好的
ServiceProvider保存到静态类的属性中,示例代码:
注意:这种方式会增加代码耦合,需谨慎使用。public static class ServiceLocator { public static IServiceProvider Instance { get; set; } } // 在Program.cs中 var provider = services.BuildServiceProvider(); ServiceLocator.Instance = provider; - 依赖注入传递:在需要访问容器的类中,直接注入
IServiceProvider(或IServiceScopeFactory用于创建作用域),示例代码:
这是符合DI设计原则的推荐方式。public class SomeService { private readonly IServiceProvider _serviceProvider; public SomeService(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public void DoSomething() { var otherService = _serviceProvider.GetRequiredService<IOtherService>(); // 业务逻辑 } }
内容的提问来源于stack exchange,提问作者LGhoul
相关产品推荐
相关产品推荐

