动态加载外部DLL时DI注册触发FileNotFoundException问题求助
解决方案
核心问题分析
当使用Microsoft.Extensions.DependencyInjection注册Service或IService时,CLR会立即尝试解析Service类型的元数据,而该类型依赖未加载的Library.DLL,此时AssemblyResolve事件尚未生效,因此抛出文件未找到异常。
配置层面的解决方案
1. 延迟服务实例化(推荐)
将服务注册改为工厂委托模式,避免在注册阶段触发Service类型的加载,直到第一次解析服务时才实例化(此时已完成Library.DLL的动态加载)。
修改注册代码:
// 移除直接注册Service的代码 // services.TryAddSingleton<Service>(); // 改用工厂委托延迟创建实例 services.TryAddSingleton<IService>(sp => { // 此代码块仅在第一次解析IService时执行,此时Library.DLL已加载 return new AppName.Infrastructure.FeatureX.Service(); });
原理:DI容器在注册时仅存储委托逻辑,不会立即尝试解析Service类型,直到调用GetRequiredService<IService>()时才执行委托,此时AssemblyResolve已生效,可正确加载Library.DLL。
2. 反射式服务注册
通过字符串类型名反射获取Service类型,避免编译时的直接类型依赖,从而推迟Library.DLL的加载时机。
修改注册代码:
// 通过反射获取Service类型(需确保程序集名称正确) var serviceImplType = Type.GetType("AppName.Infrastructure.FeatureX.Service, AppName.Infrastructure"); // 注册接口与实现类型 services.TryAddSingleton(typeof(AppName.Application.FeatureX.IService), serviceImplType);
原理:使用Type.GetType()时,CLR仅在需要创建实例时才会加载包含该类型的程序集及依赖的Library.DLL,此时AssemblyResolve事件已处理动态加载逻辑。
3. 拆分宿主构建流程
如果版本选择视图依赖DI,但可拆分宿主为轻量版和完整版:
- 第一步:构建仅包含版本选择相关服务的轻量宿主(不依赖
Library.DLL),显示版本选择视图并获取用户选定的路径。 - 第二步:设置
AssemblyResolve事件处理程序,动态加载选定版本的Library.DLL。 - 第三步:构建完整宿主,注册所有依赖
Library.DLL的服务。
示例流程:
// 1. 构建轻量宿主(仅包含版本选择ViewModel等无Library依赖的服务) var lightHostBuilder = Host.CreateDefaultBuilder() .ConfigureServices(services => { services.AddSingleton<VersionSelectionViewModel>(); }); using var lightHost = lightHostBuilder.Build(); // 2. 显示版本选择视图,获取用户选择的Library路径 var vm = lightHost.Services.GetRequiredService<VersionSelectionViewModel>(); ShowVersionSelectionWindow(vm); string selectedLibraryPath = vm.SelectedLibraryPath; // 3. 设置AssemblyResolve事件 AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { var assemblyName = new AssemblyName(args.Name); if (assemblyName.Name == "Library.DLL") { return Assembly.LoadFrom(selectedLibraryPath); } return null; }; // 4. 构建完整宿主,注册依赖Library的服务 var fullHostBuilder = Host.CreateDefaultBuilder() .ConfigureServices(services => { services.TryAddSingleton<IService, Service>(); // 其他服务注册... }); using var fullHost = fullHostBuilder.Build(); // 启动主应用逻辑 RunMainApplication(fullHost.Services);
内容的提问来源于stack exchange,提问作者Adeventure Time
相关产品推荐
相关产品推荐

