.NET 6动态加载程序集出现microsoft.extensions.configuration.binder版本冲突如何解决
针对.NET 6下动态加载类库的程序集版本冲突解决方案
最优方案:使用AssemblyLoadContext(ALC)隔离加载动态类库
.NET Core 3.0及以上版本替代AppDomain实现程序集隔离的官方方案是AssemblyLoadContext,完全可以满足你按需加载、版本不冲突的需求:
- 不同ALC可以加载同一程序集的不同版本,互不干扰:主程序默认ALC加载Serilog依赖的低版本
Microsoft.Extensions.Configuration.Binder,动态类库所在的自定义ALC加载自身依赖的6.0.0版本,不会出现版本冲突 - 完全按需加载:仅当用户触发动态类库加载逻辑时,才会创建自定义ALC并加载对应依赖的高版本程序集,未触发时不会加载任何多余程序集
- 支持卸载:将ALC标记为可回收后,动态类库使用完毕后可以卸载释放资源
代码实现
- 自定义插件加载上下文
using System.Reflection; using System.Runtime.Loader; public class PluginLoadContext : AssemblyLoadContext { private readonly AssemblyDependencyResolver _resolver; // isCollectible设为true即可支持后续卸载 public PluginLoadContext(string pluginPath) : base(isCollectible: true) { _resolver = new AssemblyDependencyResolver(pluginPath); } protected override Assembly? Load(AssemblyName assemblyName) { string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); if (assemblyPath != null) { return LoadFromAssemblyPath(assemblyPath); } // 公共基础库 fallback 到默认ALC加载,避免重复加载 return null; } protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) { string? libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName); if (libraryPath != null) { return LoadUnmanagedDllFromPath(libraryPath); } return base.LoadUnmanagedDll(unmanagedDllName); } }
- 动态加载类库逻辑(仅触发时执行)
// 替换为你的动态类库实际路径 var pluginPath = Path.Combine(AppContext.BaseDirectory, "Plugins", "YourDynamicLibrary.dll"); var customAlc = new PluginLoadContext(pluginPath); var pluginAssembly = customAlc.LoadFromAssemblyName(AssemblyName.GetAssemblyName(pluginPath)); // 后续通过反射执行插件逻辑即可
替代方案:监听AssemblyResolve事件按需加载高版本程序集
如果你的动态类库需要和主程序共享类型、不适合做ALC隔离,可以用该方案:
- 仅当动态类库请求6.0.0版本的
Microsoft.Extensions.Configuration.Binder时,才会加载对应程序集,不会提前加载 - 无需修改主程序的NuGet依赖配置
- 注意:
Microsoft.Extensions系列包官方保证向后兼容,低版本调用高版本程序集不会出现兼容性问题
代码实现
在主程序启动入口处注册事件监听:
AppDomain.CurrentDomain.AssemblyResolve += (_, args) => { var assemblyName = new AssemblyName(args.Name); if (assemblyName.Name == "Microsoft.Extensions.Configuration.Binder" && assemblyName.Version >= new Version(6, 0, 0, 0)) { // 替换为你提前部署的6.0.0版本dll的实际路径 var binderPath = Path.Combine(AppContext.BaseDirectory, "Microsoft.Extensions.Configuration.Binder.dll"); if (File.Exists(binderPath)) { return Assembly.LoadFrom(binderPath); } } return null; };
备选方案:显式指定版本
即你当前使用的在主程序中显式添加6.0.0版本Microsoft.Extensions.Configuration.Binder依赖的方案,虽然会提前加载高版本程序集,但该包体积极小,对运行时资源占用可忽略不计,如果动态类库的加载概率较高,该方案实现成本最低、稳定性最高。
内容的提问来源于stack exchange,提问作者EuroEager
相关产品推荐
相关产品推荐

