【问题标题】:How to load assemblies in different directories in dotnet core?如何在 dotnet core 的不同目录中加载程序集?
【发布时间】:2019-05-24 11:38:18
【问题描述】:

背景

我有一个在 .Net Core 2.2 上运行的大型旧 C# 应用程序,我正在尝试向它添加“hotbin”功能。我的意思是,假设我的应用程序的入口点是 A.dll,而 A.dll 依赖于 B.dll(例如,B.dll 被 A.dll 的 .csproj 文件引用),并且 A.dll 也会加载(通过 Activator.CreateInstance)来自 C.dll 的类。因此,包含完整的已部署应用程序的文件夹如下所示:

/root/
  |
  +-A.dll
  +-B.dll
  +-C.dll

也就是说,所有 dll 都在同一级别上,.NET 可以毫无问题地找到 A.dll 的依赖项。这个“hotbin”功能背后的想法是我想定义一个特殊的文件夹,将 dll 放在那里,反弹应用程序,并让应用程序加载这些 dll 而不是 root 中的等效文件。所以,回到前面的例子,假设我的文件夹结构是这样的:

/root/
  |
  +-A.dll
  +-B.dll
  +-C.dll
  +-/hotbin/
      |
      +-B.dll

当我启动 A.dll 时,我希望它从 /hotbin/ 文件夹加载 B.dll,而不是从 /root/ 文件夹加载 B.dll。

为什么我需要这个

此应用在 docker 容器中运行。如果我想测试一个错误修复,我宁愿将 dll 复制到一个文件夹中并反弹容器,然后创建一个带有错误修复的新 docker 映像并重新部署它。

我的尝试

  • 向 A.runtimeconfig.json 添加“alternateProbingPath”。起初这似乎可行,但在从 A.dll 的 deps.json 加载所有 dll 后,应用程序在从这些 dll 加载依赖 dll 时崩溃。不确定每个 dll 是否需要为它自己的依赖项设置一个 alternateProbingPath,如果他们这样做了,那么这是一个不可行的,因为这个应用程序中有很多 dll。

  • 将所有依赖的 dll 移动到 /local/ 文件夹并编写一个“A.Hotbin.dll”,它在 Activator.CreateInstance-ing A.dll 之前附加到 AssemblyResolve 事件并将控制权传递给它。

    在此设置中,应用的文件夹如下所示:

/root/
  |
  +-A.hotbin.dll
  +-A.dll
  +-/local/
      |
      +-B.dll
      +-C.dll

A.hotbin.dll 将拦截所有程序集解析失败(这种情况总是会发生,因为没有一个 dll 与 A.dll 位于同一文件夹中),检查该 dll 是否存在于 hotbin 文件夹中,然后如果它没有加载 /local/ 中的那个。同样,这几乎可以正常工作,但是在加载前几个 dll 后,应用程序会崩溃。没有堆栈跟踪,什么都没有。只是一个崩溃。附加调试器没有帮助,因为调试器导致崩溃更早发生。

  • 将所有依赖的 dll 移动到 /local/ 文件夹并修改 A.hotbin.dll 以在启动时将该文件夹中的所有 dll 加载到当前 AppDomain 中。这不起作用,因为 AppDomain.Load() 采用程序集名称,而不是路径,并且它希望这些程序集位于正常位置,即 A.hotbin.dll 旁边。

还有其他建议吗?还是有其他方法可以做到这一点?我曾想过只使用 docker cp,但问题是我需要在新的 dll 中终止应用程序以 cp,而 K8S 会自动重启它。

【问题讨论】:

    标签: c# docker .net-core


    【解决方案1】:

    我想我找到了一些似乎可行的方法。通过结合最后两个解决方案(让 A.hotbin.dll 拦截所有解析失败,并让 A.hotbin.dll 在启动时加载 /local/ 中的所有 dll),看起来我至少能够启动应用程序和运行。我会进一步测试以确保它确实正常工作,如果是这样的话,我会编辑这个答案。

    编辑:是的,看起来可行。为了将来参考,这是我所拥有的:

    /root/
      |
      +- A.dll
      +- A.hotbin.dll
      +-/local/
          |
          +-B.dll
          +-C.dll
    

    我执行 A.hotbin.dll 而不是 A.dll。 A.hotbin.dll 为AppDomain.CurrentDomain.AssemblyResolve 添加了解析失败的钩子。这个钩子在 /local/ 文件夹中查找 dll,如果找到,则返回它。如果不是,则返回 null(允许继续正常的 dll 解析)。 A.hotbin.dll 然后进入本地文件夹并迭代在那里找到的所有 dll。对于每个 dll,它会尝试通过AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName(dllfilename)) 将其加载到当前的 AppDomain 中。这个调用将无法解析 dll,所以它会调用我的钩子,它会找到它。所有dll都加载完毕后,A.hotbin.dll Activator.CreateInstance-es A.dll 并把控制权交过去。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-16
      • 1970-01-01
      • 1970-01-01
      • 2010-11-20
      • 2017-04-15
      • 1970-01-01
      • 2011-01-09
      • 1970-01-01
      相关资源
      最近更新 更多