【问题标题】:.NET Load assemblies at runtime Again.NET 在运行时再次加载程序集
【发布时间】:2023-03-23 12:16:01
【问题描述】:

我不久前发布了一个类似的问题。我需要在运行时加载程序集。

如果我知道运行时 dll 的绝对路径,这很容易。

但我不 :( 如果文件不在应用程序根目录中,则 assembly.Load() 或 LoadFromFile() 失败。

我唯一拥有的是 dll 名称。 dll 可能位于根目录、system32 甚至 GAC 中。

.net 是否可以自动确定 dll 的位置,例如: 它应该首先查看根目录。如果它不存在,请转到系统文件夹,否则请尝试 GAC。

已编辑

我正在使用插件架构。我不需要注册 dll。我有一个多用户应用程序。我有一个应用程序表,其中包含有关应用程序的信息。每个应用程序都有一个与之关联的 dll 路径,其中包含与该应用程序关联的某些算法。希望这会有所帮助。

【问题讨论】:

    标签: c# .net reflection assemblies


    【解决方案1】:

    当前应用程序查找程序集时,它会在多个位置(bin 文件夹、gac 等)查找。如果找不到,则开发人员需要手动告诉应用程序在哪里查找。您可以通过拦截 AssemblyResolve 事件并使用事件参数告诉 CLR 您的程序集在哪里来做到这一点。

    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    ....................
    Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
       var strTempAssmbPath=
              Path.GetFullPath("C:\\Windows\\System32\\" + args.Name.Substring(0,  args.Name.IndexOf(",")) + ".dll");
    
       var strTempAssmbPath2=
              Path.GetFullPath("C:\\Windows\\" + args.Name.Substring(0,  args.Name.IndexOf(",")) + ".dll");
    
    
        if (File.Exists(strTempAssmbPath))
                return Assembly.LoadFrom(strTempAssmbPath);
    
        if (File.Exists(strTempAssmbPath2))
                return Assembly.LoadFrom(strTempAssmbPath2);
    }
    

    【讨论】:

      【解决方案2】:

      您可以连接到AppDomain.CurrentDomain.AssemblyResolve 事件并按需手动为您的应用程序加载程序集。

      【讨论】:

      • 好的,一旦我设置了所有额外的路径 - 我如何告诉 CLR 加载程序集?我还使用 Load() 方法吗?
      • 完全...但是除了您的应用程序目录和 GAC 之外,它还会自动搜索这些文件夹中的程序集。
      • FWIW 虽然支持 AppDomainSetup.PrivateBinPath,但不推荐使用上述方法。见msdn.microsoft.com/en-us/library/…
      • 私有路径或相对搜索路径是相对于程序集解析器探测私有程序集的基目录的路径。您上面的解决方案不起作用。
      • @Leyu,谢谢。你是对的,很久以前我就是这样做的。答案的第一部分已删除。
      【解决方案3】:

      是的,有一种方法,它取决于您的 dll 是弱命名(没有公钥令牌)还是强命名(使用公钥令牌)。如果它的名称很弱,并且您在 VS 中使用 dll 添加了对程序集的引用,那么 VS 将首先在应用程序文件夹根目录中查找,如果找不到,它将在您指定为值的子目录中查找您的 XML 配置文件中的 privatePath 属性。

      如果它是一个强命名的 dll,则 CLR 将在 GAC 中搜索,因此您需要在 GAC 中安装该 dll。如果您安装一个 XML 配置文件,其 codeBase 元素指向 dll 的路径,CLR 也可以查看应用程序目录。

      要在 GAC 中指定程序集,您可以在编译程序集时使用 /reference:[DLL name] 开关。

      【讨论】:

      • 如果它是弱命名的,我没有在VS中添加程序集的引用怎么办?
      • 他不能使用 /reference,因为他在运行时加载 DLL。/ref 开关也适用于任何 ref 程序集(无论 GAC 或私有)
      【解决方案4】:

      如果 dll 位于 PATH 系统变量(即 system32)中引用的某个位置,或者如果 dll 已注册,则会自动找到该 dll。如果它可以在磁盘上任何地方,您就找不到它,但无论如何都没有人需要该功能。

      编辑:可以注册 dll 吗?如果您不提前知道程序集,您如何获得程序集名称?您是否正在创建某种类型的插件架构?我认为如果你能多解释一下你的情况会有所帮助。

      EDIT2:如果是这样,为什么不提供一种方法让用户注册他或她的插件?您可以从打开的文件对话框中获取所需的所有信息。或者只是让他们将其转储到您指定的文件夹中。

      【讨论】:

      • 当我调用 assembly.Load("myassembly.dll") 并将 dll 放入我的 system32 时,它不起作用。
      • 我认为这适用于非托管 DLL 而非托管 DLL。请参阅 Lonzo 的帖子,了解我认为更好的回应。
      【解决方案5】:

      希望您已阅读以下内容。我的建议...

      • How the runtime locates assemblies
      • 您可以试一试Assembly.LoadWithPartialName.. 可能有用.. it says it will search the application folder and the GAC 与 Assembly.Load 不同。 (但是它的安全性较低..因为您没有指定程序集名称的所有 4 个部分,因此您最终可能会得到错误版本的 DLL)
      • 还可以尝试 AppDomainSetup.PrivateBinPath(AppDomain.AppendPrivatePath 已被弃用以支持此操作)将应用程序根目录的子文件夹添加到要探测程序集的文件夹列表中。您也可以尝试将其他地方的文件复制到 [AppFolder]\MySandboxForDLLsToLoad 中,该文件已添加到 PrivateBinPath。

      【讨论】:

        【解决方案6】:

        你有三个选择

        1. 在全局程序集缓存 (GAC) 中安装程序集
        2. 使用带有标签的应用程序配置 (.config) 文件
        3. 使用 AssemblyResolve 事件

        您可以找到详细信息here

        【讨论】:

          【解决方案7】:

          .NET 用于查找程序集及其依赖项的解析算法非常简单。

          1. .NET 标识所需的版本。通常有关依赖程序集的信息存在于应用程序的程序集清单中。
          2. .NET 搜索 GAC(全局程序集缓存),仅当程序集是强命名时。
          3. 如果在 GAC 中未找到,并且存在 .config 文件,则 .NET 搜索配置文件中指定的位置,否则 .NET 搜索包含可执行文件 (.EXE) 的目录
          4. 在此之后,如果仍然找不到程序集,应用程序将因错误而终止。

          Click here 用于解释 .net 分辨率算法的视频,click here 用于有关后期绑定程序集的视频

          【讨论】:

            【解决方案8】:

            将此程序集注册到 GAC。 How to do that

            【讨论】:

              【解决方案9】:

              使用这个 Assembly.LoadWithPartialName(assemblyName);

              【讨论】:

                猜你喜欢
                • 2018-04-24
                • 2010-10-05
                • 2012-08-02
                • 1970-01-01
                • 1970-01-01
                • 2011-09-09
                • 1970-01-01
                相关资源
                最近更新 更多