.NET在运行时加载程序集

4
我之前发布过相似的问题。我需要在运行时加载程序集。
如果我在运行时知道Dll文件的绝对路径,这很容易实现。
但是我不知道 :( 如果文件不在应用程序根目录中,则assembly.Load()或LoadFromFile()无法成功加载。
我唯一拥有的东西就是dll名称。该dll可能位于根目录、system32甚至GAC中。
像下面这样,.net是否能自动确定dll的位置:
首先,在根目录查找。如果它不在那里,请继续尝试系统文件夹,否则请尝试GAC。
编辑
我正在使用插件架构。我不需要注册dll。我有一个多用户应用程序。我有一个包含有关应用程序信息的应用程序表。每个应用程序都有与之相关联的dll路径,其中包含与该应用程序相关的某些算法。希望这有所帮助。
9个回答

2
你可以通过挂钩 AppDomain.CurrentDomain.AssemblyResolve 事件,在需要时手动加载应用程序的程序集。

好的,一旦我设置了所有额外的路径 - 我该如何告诉CLR加载程序集?我仍然使用Load()方法吗? - MegaByte
除了您的应用程序目录和全局程序集缓存 (GAC) 外,它还会自动在这些文件夹中搜索程序集。 - lubos hasko
1
以上方法已被弃用,现在推荐使用AppDomainSetup.PrivateBinPath。请参阅http://msdn.microsoft.com/en-us/library/system.appdomain.appendprivatepath.aspx。 - Gishu
私有路径或相对搜索路径是程序集解析器探测私有程序集的基本目录相对路径。您上面的解决方案不起作用。 - Leyu
1
@Leyu,谢谢。你说得对,我做这个已经很久了。回答的第一部分已经删除。 - lubos hasko

2

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

  • 运行时如何定位程序集
  • 您可以尝试使用Assembly.LoadWithPartialName,它可能会起作用。它说它将搜索应用程序文件夹和GAC,与Assembly.Load不同。(但它不太安全,因为您可能会得到错误版本的DLL,因为您没有指定程序集名称的所有4个部分)
  • 还可以尝试使用AppDomainSetup.PrivateBinPath(AppDomain.AppendPrivatePath已被弃用),将应用程序根目录的子文件夹添加到探测程序集的文件夹列表中。您还可以尝试将其他位置的文件复制到[AppFolder]\MySandboxForDLLsToLoad中,该文件夹将添加到PrivateBinPath中。

2

当当前应用程序查找程序集时,它会在几个位置查找(bin文件夹、全局程序集缓存等)。如果找不到,开发人员需要手动告诉应用程序在哪里查找。您可以通过拦截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);
}

1

你有三个选项:

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

你可以在 这里 找到详细信息。


1

如果dll位于PATH系统变量(例如system32)引用的某个位置或已注册,则将自动找到该dll。如果dll可以在磁盘上的任何地方,则无法找到它,但是无论如何也不需要该功能。

编辑:dll是否可以注册?如果您事先不知道程序集的名称,您是如何获取程序集名称的?您是否正在创建某种类型的插件架构?如果您解释一下您的情况会有所帮助。

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


当我调用assembly.Load("myassembly.dll")并将dll文件放在我的system32目录下时,它无法正常工作。 - MegaByte
我认为这对于非托管的 DLLs 是有效的,而不是托管的 DLLs。请参考 Lonzo 的帖子,了解我认为更好的响应是什么。 - Gishu

1

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

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

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


如果它的命名不规范并且我没有在VS中添加程序集的引用,那该怎么办? - MegaByte
他无法使用/reference,因为他在运行时加载DLL。此外,/ref开关适用于任何ref程序集(无论是GAC还是私有)。 - Gishu

1

.NET使用的解析算法来查找程序集及其依赖项是直截了当的。

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

点击此处观看解释.NET解析算法的视频,点击此处观看有关延迟绑定程序集的视频。


0

将此程序集注册到全局程序集缓存中。如何操作


0
使用以下代码: Assembly.LoadWithPartialName(assemblyName);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接