通过AssemblyResolve加载程序集为何出现方法未找到异常?
问题描述
我开发了一款从其他文件夹动态加载DLL的应用,目标DLL(MyDLL.dll)依赖Microsoft.Extensions.Logging.dll。直接先加载依赖DLL再加载目标DLL时,调用方法正常运行;但通过AppDomain的AssemblyResolve事件加载依赖DLL时,调用目标DLL方法会触发MissingMethodException,提示找不到指定的AddConsole方法。已确认两种方式加载的依赖程序集路径完全一致,想知道为什么表现不同?
正常运行代码示例
void f() { Assembly.LoadFrom(@"C:\DllFolder\Microsoft.Extensions.Logging.dll"); Assembly mydll = Assembly.LoadFrom(@"C:\DllFolder\MyDLL.dll"); CallMethodFromMyDll(mydll); // 运行正常 :-) }
异常场景代码示例
void f() { AppDomain.CurrentDomain.AssemblyResolve += MyAssemblyResolveFunction; Assembly mydll = Assembly.LoadFrom(@"C:\DllFolder\MyDLL.dll"); CallMethodFromMyDll(mydll); // 触发MissingMethodException :-( } Assembly MyAssemblyResolveFunction(object sender, ResolveEventArgs args) { var assembly = Assembly.LoadFrom(@"C:\DllFolder\Microsoft.Extensions.Logging.dll"); if (assembly != null) { // 代码确实执行到这里了! return assembly; } return null; }
异常信息
Method not found: 'Microsoft.Extensions.Logging.ILoggerFactory Microsoft.Extensions.Logging.ConsoleLoggerExtensions.AddConsole(Microsoft.Extensions.Logging.ILoggerFactory, Microsoft.Extensions.Logging.LogLevel)'.
原因分析与解决方案
核心问题:程序集绑定上下文不匹配
直接调用Assembly.LoadFrom加载依赖DLL时,程序集会被加载到加载上下文(Load Context)中;而通过AssemblyResolve事件返回的程序集,默认会被加载到无上下文(No Context)中。
MyDLL.dll编译时引用的是加载上下文中的Microsoft.Extensions.Logging.dll,当运行时依赖的程序集处于无上下文时,CLR会认为这是两个不同的程序集实例——即使它们路径相同、版本一致,也会因为上下文差异导致方法绑定失败,触发MissingMethodException。
验证方式
你可以在两种场景下分别输出Microsoft.Extensions.Logging.dll的Assembly.LoadContext属性值,会发现直接加载时属于DefaultLoadContext,而通过AssemblyResolve返回的则是null(无上下文)。
修复方案
修改AssemblyResolve事件中的加载方式,确保依赖DLL被加载到加载上下文:
Assembly MyAssemblyResolveFunction(object sender, ResolveEventArgs args) { // 使用AssemblyLoadContext.Default.LoadFromAssemblyPath替代LoadFrom var assemblyPath = @"C:\DllFolder\Microsoft.Extensions.Logging.dll"; return AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); }
或者,也可以提前将依赖DLL的路径添加到应用的程序集探测路径,让CLR自动找到并加载到正确上下文:
// 在加载MyDLL前执行 AppDomain.CurrentDomain.AppendPrivatePath(@"C:\DllFolder");
内容的提问来源于stack exchange,提问作者user3570224

