使用Scrutor加载外部程序集依赖项的问题求助
解决外部程序集依赖加载问题
完全可行,核心思路是利用CLR的程序集解析事件,当CLR无法找到依赖程序集时,手动从指定外部文件夹加载对应的依赖文件。以下是具体实现方案:
步骤1:注册全局程序集解析事件
在加载外部程序集前,注册AppDomain.CurrentDomain.AssemblyResolve事件——该事件会在CLR找不到所需程序集时触发,我们可以在事件处理逻辑中从外部文件夹查找并加载依赖。
步骤2:修改扩展方法并实现解析逻辑
调整原扩展方法,补充依赖解析的逻辑,同时优化程序集加载方式:
public static IImplementationTypeSelector FromExternalAssemblies( this IAssemblySelector selector, ConfigurationManager configurationManager) { var virgilioMainFolder = configurationManager["ExternalFolder:Folder"]; var assembliesToLoad = new List<string>(); configurationManager.GetSection("ExternalFolder:AssembliesToLoad") .Bind(assembliesToLoad); var assemblies = new List<Assembly>(); // 确保事件只注册一次,避免重复调用时触发多次逻辑 AppDomain.CurrentDomain.AssemblyResolve -= ResolveExternalAssembly; AppDomain.CurrentDomain.AssemblyResolve += ResolveExternalAssembly; foreach (var pathAssembly in assembliesToLoad) { try { var fullPathAssembly = Path.Combine(virgilioMainFolder, pathAssembly); // 用LoadFrom替代LoadFile:LoadFrom会尝试加载直接依赖(同文件夹下),减少解析压力 var assembly = Assembly.LoadFrom(fullPathAssembly); assemblies.Add(assembly); } catch (Exception) { continue; } } return selector.FromAssemblies(assemblies.ToArray()); // 局部方法:处理依赖程序集的解析逻辑 Assembly? ResolveExternalAssembly(object? sender, ResolveEventArgs args) { var assemblyName = new AssemblyName(args.Name); // 拼接依赖程序集的路径 var assemblyPath = Path.Combine(virgilioMainFolder, $"{assemblyName.Name}.dll"); if (File.Exists(assemblyPath)) { return Assembly.LoadFrom(assemblyPath); } // 若依赖分布在子文件夹,可扩展此处逻辑(比如递归遍历外部文件夹) return null; } }
关键细节说明
- LoadFrom与LoadFile的区别:
LoadFile仅加载指定的单个程序集,完全不处理依赖;LoadFrom会自动加载同文件夹下的直接依赖,能减少一部分解析工作。 - 事件幂等性:先移除再添加事件处理程序,避免多次调用扩展方法时重复注册,导致逻辑重复执行。
- 强命名程序集处理:如果依赖是强命名程序集,要确保版本、公钥令牌与引用要求完全匹配,否则CLR会拒绝加载。
- 异常防护:实际使用时建议在
ResolveExternalAssembly中添加异常捕获,避免单个依赖加载失败导致整个应用崩溃。
额外注意事项
- 若依赖程序集已被主应用域加载过,CLR会直接复用已加载的版本,不会触发解析事件。
- 若是插件化场景,后续卸载插件时建议移除事件处理程序,避免内存泄漏(长期运行的服务需重点关注)。
内容的提问来源于stack exchange,提问作者lunatic84
相关产品推荐
相关产品推荐

