You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Assembly Load Context下TPL.DataFlow加载异常及AssemblyResolve疑问

问题:TPL.DataFlow.dll加载异常排查疑惑

加载引用TPL.DataFlow库的程序集时,遇到TPL.DataFlow.dll无法加载的问题。根据微软文档,使用Assembly.LoadFrom()时,程序集所在文件夹会被纳入Assembly Load Context的考量范围。我通过AssemblyResolve事件解决了该问题,但调试时发现并未进入if (assembly == null)分支——也就是程序集已加载到上下文却未被解析,对此存在疑惑。

相关代码

public static IService LoadService(CtorParameters parameters)
{
    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        CurrentDomain_AssemblyResolve(sender, args, parameters.DllLocation);
    try
    {
        var assembly = Assembly.LoadFrom(parameters.DllLocation);
        var serviceType = assembly.GetType(SERVICE_TYPE);
        var serialPortInstance = (IService)Activator.CreateInstance(serviceType, parameters);
        return serialPortInstance;
    }
    finally
    {
        AppDomain.CurrentDomain.AssemblyResolve -= (sender, args) =>
            CurrentDomain_AssemblyResolve(sender, args, parameters.DllLocation);
    }
}

private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args, string loadedAssemblyPath)
{
    var appDomain = (AppDomain)sender;
    if (args.RequestingAssembly == null)
    {
        try
        {
            var assemblyName = new AssemblyName(args.Name);
            var assembly = appDomain.GetAssemblies().FirstOrDefault(m => m.GetName().Name == assemblyName.Name);
            if (assembly == null)
            {
                var loadedDllDir = Path.GetDirectoryName(loadedAssemblyPath);
                var dllPath = Path.Combine(loadedDllDir, $"{assemblyName}.dll");
                assembly = Assembly.LoadFrom(dllPath);
            }
            return assembly;
        }
        catch { }        
    }
    return args.RequestingAssembly;
}

原因分析与解释

  1. 上下文不匹配导致的解析触发:Assembly.LoadFrom()加载的程序集会被放入LoadFrom上下文,而CLR解析依赖时,优先在默认加载上下文(应用程序基目录、探测路径下的程序集)查找。即便TPL.DataFlow.dll已经在LoadFrom上下文加载,默认上下文没有匹配项时,CLR仍会触发AssemblyResolve事件。此时你的代码通过appDomain.GetAssemblies()能找到已加载的实例,自然不会进入if (assembly == null)分支。

  2. AssemblyResolve事件的触发逻辑:只要CLR在预期上下文找不到依赖,就会触发事件,不管该程序集是否在其他上下文存在。你的代码返回已加载的程序集实例,相当于告诉CLR“用这个现成的”,问题得以解决,但不会执行到重新加载的分支。

  3. args.RequestingAssembly == null判断的隐患:TPL.DataFlow.dll是被你加载的主程序集引用的,此时args.RequestingAssembly应该不为null——但你的代码直接返回args.RequestingAssembly,这其实无法解决依赖问题。之所以问题能解决,大概率是事件触发了多次,某次触发时appDomain.GetAssemblies()已能找到目标程序集。

优化建议

  • 移除args.RequestingAssembly == null的判断,否则无法处理主程序集引用的依赖解析场景。
  • 不要在finally块中移除AssemblyResolve事件:Activator.CreateInstance可能触发延迟加载的依赖,此时事件已被移除,会导致新的加载失败。
  • 可以通过AssemblyName的Location属性确认程序集加载路径,避免跨上下文解析的混乱。

内容的提问来源于stack exchange,提问作者JuanDYB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 10:07:45