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

.NET Framework4.8动态加载插件时同目录Google.Protobuf.dll加载失败

问题背景

基于.NET Framework 4.8开发的C#应用,使用ClearScript库支持JavaScript作为扩展语言,可将功能封装为DLL插件在运行时动态挂载,核心挂载逻辑代码如下:

JSE.Script.attach = (Func<string, bool>)Attach;
...
        private static bool Attach(string dllPath, string name = "")
        {
            var status = false;
            var htc = new HostTypeCollection();
            try
            {
                var assem = Assembly.Load(AssemblyName.GetAssemblyName(dllPath));
                htc.AddAssembly(assem);
                if (name.Length == 0)
                {
                    name = assem.FullName.Split(',')[0];
                }

                JSE.AddHostObject(name, htc); //FIXME checkout the hosttypes
                Console.Error.WriteLine($"Attached {dllPath} as {name}");
                status = true;
            }
            catch (ReflectionTypeLoadException rtle)
            {
                foreach (var item in rtle.LoaderExceptions)
                {
                    Console.Error.WriteLine(item.Message);
                    T.Fail(item.Message);
                }

            }
            catch (FileNotFoundException fnfe)
            {
                Console.Error.WriteLine(fnfe.Message);
                T.Fail(fnfe.Message);

            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.Message);
                T.Fail(e.Message);

            }
            return status;
        }

插件调用方式

JavaScript脚本中通过如下形式调用插件能力:

attach(".\\Plugin_GoogleAds_Metrics.dll");
H = Plugin_GoogleAds_Metrics.GoogleAds_Metrics.Historical;
H.EnableTrace("GAM");
...

异常现象

执行插件的GetAccountInformation方法,运行至GoogleAdsServiceClient googleAdsService = client.GetService(Services.V11.GoogleAdsService);代码行时抛出错误,提示无法加载Google.Protobuf程序集,完整异常信息如下:

Exception has been thrown by the target of an invocation.
    at JScript global code (Script [23] [temp]:5:0) -> acc = H.GetAccountInformation(auths.Item1, 7273576109, true)
   at Microsoft.ClearScript.ScriptEngine.ThrowScriptError(IScriptEngineException scriptError)
   at Microsoft.ClearScript.Windows.WindowsScriptEngine.ThrowScriptError(Exception exception)
   at Microsoft.ClearScript.Windows.WindowsScriptEngine.<>c__DisplayClass57_0`1.<ScriptInvoke>b__0()
   at Microsoft.ClearScript.ScriptEngine.ScriptInvokeInternal[T](Func`1 func)
   at Microsoft.ClearScript.ScriptEngine.ScriptInvoke[T](Func`1 func)
   at Microsoft.ClearScript.Windows.WindowsScriptEngine.ScriptInvoke[T](Func`1 func)
   at Microsoft.ClearScript.Windows.WindowsScriptEngine.Execute(UniqueDocumentInfo documentInfo, String code, Boolean evaluate)
   at Microsoft.ClearScript.Windows.JScriptEngine.Execute(UniqueDocumentInfo documentInfo, String code, Boolean evaluate)
   at Microsoft.ClearScript.ScriptEngine.Evaluate(UniqueDocumentInfo documentInfo, String code, Boolean marshalResult)
   at Microsoft.ClearScript.ScriptEngine.Evaluate(DocumentInfo documentInfo, String code)
   at Microsoft.ClearScript.ScriptEngine.Evaluate(String documentName, Boolean discard, String code)
   at Microsoft.ClearScript.ScriptEngine.Evaluate(String documentName, String code)
   at Microsoft.ClearScript.ScriptEngine.Evaluate(String code)
   at RulesetRunner.Program.Run(JScriptEngine& jSE, String scriptText, Config cfg, Dictionary`2 settings) in C:\Users\bugma\Source\Repos\Present\BORR\RulesetRunner\RunManagementPartials.cs:line 72
Exception has been thrown by the target of an invocation.
Exception has been thrown by the target of an invocation.
Could not load file or assembly 'Google.Protobuf, Version=3.15.8.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604' or one of its dependencies. The system cannot find the file specified.

已完成排查项

  • 项目已引用最新版本的Google.Ads.GoogleAds库
  • 插件项目csproj文件中已设置AutoGenerateBindingRedirects为true
  • 已在插件项目上下文中执行Add-BindingRedirect命令
  • Plugin_GoogleAds_Metrics.dll与Google.Protobuf.dll确实位于同一目录下

排查解决步骤
  1. 补全程序集探测路径逻辑
    你现在用Assembly.Load加载插件时,CLR默认不会主动扫描插件DLL所在目录下的依赖,哪怕依赖和插件放在同一个文件夹也不会识别,这是.NET动态加载插件最常见的坑。
    在主程序入口初始化阶段,注册AssemblyResolve事件手动处理依赖加载,不要把这段逻辑写在Attach方法里:

    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
    {
        var targetAsmName = new AssemblyName(args.Name).Name;
        // 替换为你实际存放插件的目录路径
        var pluginRoot = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        var targetPath = Path.Combine(pluginRoot, $"{targetAsmName}.dll");
        return File.Exists(targetPath) ? Assembly.LoadFrom(targetPath) : null;
    };
    

    这里用LoadFrom而不是Load,可以让CLR正确识别加载上下文,避免同程序集不同路径重复加载的问题。

  2. 把绑定重定向配置移到主程序
    你之前在插件项目里开的自动绑定重定向、执行的PowerShell重定向命令全部不生效——.NET Framework的绑定重定向规则只会读取主入口EXE的配置文件,类库项目的App.config、生成的绑定重定向配置会被CLR完全忽略。
    打开主程序项目的App.config,在runtime节点下手动添加Google相关依赖的绑定重定向,版本号填你实际输出目录下对应DLL的真实版本,示例:

    <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <dependentAssembly>
          <assemblyIdentity name="Google.Protobuf" publicKeyToken="a7d26565bac4d604" culture="neutral" />
          <bindingRedirect oldVersion="0.0.0.0-3.25.3.0" newVersion="3.25.3.0" />
        </dependentAssembly>
        <!-- Google.Ads.GoogleAds、Google.Api.Common等其他相关依赖按相同格式补全 -->
      </assemblyBinding>
    </runtime>
    

    重新生成主程序后,确认输出目录下[你的主程序名].exe.config文件里存在上述配置,不要只改插件项目的配置文件。

  3. 校验依赖完整性和版本匹配
    用ILSpy或Dependencies工具打开插件目录下的两个文件做校验:

    • 查看Plugin_GoogleAds_Metrics.dll引用的Google.Protobuf版本号,和目录下实际存在的Google.Protobuf.dll版本号是否匹配
    • 检查Google.Protobuf.dll自身的依赖是否齐全,重点确认System.Memory、System.Runtime.CompilerServices.Unsafe这两个基础类库是否存在、版本是否匹配,很多时候Protobuf加载失败是因为它自身的依赖缺失,不是Protobuf本身找不到。
  4. 预加载插件依赖避免懒加载异常
    你当前的Attach方法只把插件本身的程序集加入了HostTypeCollection,依赖程序集没有提前加载到AppDomain时,ClearScript遍历宿主类型做映射、或者JIT编译插件方法时会触发隐性的加载失败。可以在加载完插件主DLL后,遍历插件目录下的所有相关DLL做预加载,避免调用时才触发懒加载报错。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 11:03:14