【问题标题】:How to access Fody/Costura embedded libraries at runtime from a different AppDomain如何在运行时从不同的 AppDomain 访问 Fody/Costura 嵌入式库
【发布时间】:2020-02-26 06:08:54
【问题描述】:

我需要为我的解决方案创建一个新的 AppDomain,以便我可以从它自己的 AppDomain 调用该方法。我的解决方案的所有依赖 .dll 文件都已使用 Fody/Costura 嵌入到 my.exe 中。我创建了一个Loader : MarshalByRefObject 类来调用我的方法,但是当我在运行时执行加载程序时,我得到一个异常:

无法加载文件或程序集 'my.Assembly, Version=19.1.7242.23931, Culture=neutral, PublicKeyToken=null' 或其依赖项之一。该系统找不到指定的文件。

代码正在我的 AppDomain.CurrentDomain.BaseDirectory 中查找 .dll 文件以通过加载程序执行我的方法,但它们不存在但嵌入在可执行文件中。有没有办法让我的新 AppDomain 了解已嵌入到我的可执行文件中的程序集,而无需从 BaseDirectory 加载它们?

我已经寻找将其他程序集加载到我的新 AppDomain 中的方法,但还没有找到方法。我还怀疑可能有 Fody/Costura API 可以做到这一点,但还没有找到适用于这种情况的任何东西。

        internal class Loader : MarshalByRefObject
        {
            object CallInternal(string dll, string typename, string method, object[] parameters)
            {

                Assembly a = Assembly.LoadFile(dll);
                Type t = a.GetType(typename);
                MethodInfo m = t.GetMethod(method);
                Console.WriteLine("Invoking " + m.Name);
                return m.Invoke(null, parameters);
            }

            public static object Call(string dll, string typename, string method, params object[] parameters)
            {
                object result = null;
                try
                {
                    AppDomain newAppDomain = AppDomain.CreateDomain("myNewDomain", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation);
                    Loader ld = (Loader)newAppDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(Loader).FullName);  //DLL file not found exception thrown from here
                    result = (Loader)ld.CallInternal(dll, typename, method, parameters);
                    AppDomain.Unload(newAppDomain);
                }
                catch (Exception ee)
                {
                    Console.WriteLine("Exception Message [" + ee.Message + "]");
                    PDFUtil.Report.ErrSilent(ee);
                }
                return result;
            }
        }

我希望实例化我的 Loader 类,而无需在运行时从磁盘加载 .dll。使用 Fody/Costura 嵌入式 .dll 可以做到这一点吗?

【问题讨论】:

  • 您正在加载的 dll 是否使用其他 dll?那些 dll 在基本目录中吗? Net 可执行文件在与可执行文件(而不是基本文件夹)相同的文件夹中查找其他 dll。为确保加载最新版本的可执行文件,请始终使用菜单添加其他 dll:添加现有项,然后浏览到编译可执行文件的位置。然后使用解决方案资源管理器打开参考文件夹并右键单击现有项目并复选框复制到可执行文件夹。
  • 是的,包含我尝试调用的方法的类需要 3 个 .dll 文件。这 3 个程序集已加载到当前 AppDomain 中,但在我的新 AppDomain 中不可用。因此,当我将 CreateInstanceAndUnwrap() 与我的新 AppDomain 一起使用时,它会引发 FileNotFound 异常。我想因为它没有在我的新 AppDomain 中找到程序集,所以它会在基本文件夹中查找它。 CreateInstanceAndUnwrap() .
  • 如果我将这些 .dll 放入基本文件夹,代码可以工作,因为它正在那里寻找 .dll,但它违背了嵌入 .dll 的目的,因为我将提供包含这些的更大的可执行文件.dlls(在当前 AppDomain 中),但还必须将三个 .dll 分别安装到基本目录中,以便 .exe 可以在运行时找到它们。我宁愿找到一种方法在运行时将程序集从原始 AppDomain 添加到我的新 AppDomain,而不必从磁盘加载它们,这样我就可以只提供一个 .exe 文件。有没有办法用 Fody/Costura 做到这一点?。
  • 不确定。每次启动应用程序时都要下载吗?您要问的似乎是“在运行时将程序集从原始 AppDomain 添加到我的新 AppDomain”和“我只能提供一个 .exe 文件”的冲突。
  • 在 .exe 中有当前的 AppDomain。我在同一个 .exe 中创建了第二个 AppDomain。因为它是一个新的 AppDomain,所以它没有原始 AppDomain 所具有的任何程序集。为了使用反射来调用我的方法,我需要新 AppDomain 中的一些依赖程序集。试图弄清楚如何加载它们而不必从硬盘驱动器加载 .dll。所有这些都发生在同一个.exe 中。

标签: c# dll appdomain fody-costura


【解决方案1】:

我将我的 .dll 添加到我的 Visual Studio 项目中并将 Build-Action 设置为嵌入式资源

我正在运行这段代码以将程序集放入我的新 AppDomain:

string resName = null;
foreach (string resourceName in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
   Console.WriteLine("Assembly.GetExecutingAssembly().GetManifestResourceNames() [" + resourceName + "] ");
   if (resourceName.Contains("my.Assembly"))
   {
      resName = resourceName;
      Console.WriteLine("CurrentDomain Assembly my.Assembly [" +  "] Resource name [" + resName + "]");
    }

}
Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(resName);
if (s != null)
{
    byte[] data = new BinaryReader(s).ReadBytes((int)s.Length);
    Assembly a = Assembly.Load(data);
    newAppDomain.Load(data);

     foreach (Assembly cdAssem in newAppDomain.GetAssemblies())
     {
        Console.WriteLine("newAppDomain Assembly 2 [" + cdAssem.GetName().FullName + "]");
      }
}

我可以看到该程序集是我的新 AppDomain 的一部分:

newAppDomain 程序集 2 [mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]

newAppDomain 程序集 2 my.Assembly 版本=19.1.7243.19014, Culture=neutral, PublicKeyToken=null]

但是使用 CreateInstanceAndUnwrap() 仍然失败,说它找不到 my.Assembly.dll。我想知道是否可以将程序集加载到 AppDomain 的唯一方法是从基本目录加载它?

【讨论】:

  • 向当前项目添加另一个项目时,有多种方法。 1)从第二个项目复制所有可执行文件或在第一个项目中引用第二个项目的路径。您经常使用相对路径,例如 ../../secondProj/bin/debug/abc.exe。
  • 您能否解释一下您的答案,例如您将此代码放在哪里。是否在 static void main() 中。你在 VS.Resources 下添加了 dll。基本上,我需要知道如何将您的答案与您在问题中发布的代码一起使用。我在使用 Costura 构建 exe 时遇到了同样的问题,但是当我运行它时,出现错误 Cannot resolve dependency to assembly 'Ranor exWrapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it has not been preloaded. 我环顾四周,但找不到任何与 Fody/Costura 相关的解决方案。感谢任何帮助。
猜你喜欢
  • 2019-03-02
  • 1970-01-01
  • 2020-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多