创建自定义的AppDomain并将程序集添加到其中

9
我该如何创建一个应用程序域,向其添加程序集,然后销毁该应用程序域?以下是我尝试过的方法:
    static void Main(string[] args)
    {           
        string pathToExe = @"A:\Users\Tono\Desktop\ConsoleApplication1.exe";

        AppDomain myDomain = AppDomain.CreateDomain("MyDomain");

        Assembly a = Assembly.Load(System.IO.File.ReadAllBytes(pathToExe));

        myDomain.Load(a.FullName); // Crashes here!            
    }

我也尝试过以下方法:

myDomain.Load(File.ReadAllBytes(pathToExe)); 

如何向应用程序域添加程序集。一旦完成这个步骤,就可以通过反射找到方法并执行,然后销毁应用程序域。
所得到的异常是:
“无法加载文件或程序集 'ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' 或该程序集的某一个依赖项。系统找不到指定的文件。”

2
将程序集加载到自己的域中要容易得多 - 因此,与其试图将程序集推入其他域中,不如在其他域中运行一些代码以加载您想要的任何程序集(不要忘记您可能需要预加载依赖项或正确设置程序集搜索路径)。 - Alexei Levenkov
“或其依赖项”是常见的问题。如果您不知道可能是什么,请使用Fuslogvw.exe。并使用AppDomainSetup设置正确的私有路径。 - Hans Passant
1个回答

11

两个要点:

  1. AppDomain.Load 加载一个程序集到当前 AppDomain,而不是 myDomain(很奇怪,我知道)。
  2. AppDomain.LoadLoad 上下文中加载一个程序集,该上下文从应用程序的基目录、私有二进制路径和 GAC 解析程序集。很可能,您尝试加载的程序集未位于这些位置之一,因此导致异常消息。

更多信息,请参阅此答案

将程序集加载到 AppDomain 的一种方法是创建一个派生自 MarshalByRef 的加载器。您需要像这样的东西来避免将类型(和程序集)泄漏到主 AppDomain 中。这里是一个简单的例子:

public class SimpleAssemblyLoader : MarshalByRefObject
{
    public void Load(string path)
    {
        ValidatePath(path);

        Assembly.Load(path);
    }

    public void LoadFrom(string path)
    {
        ValidatePath(path);

        Assembly.LoadFrom(path);
    }

    private void ValidatePath(string path)
    {
        if (path == null) throw new ArgumentNullException("path");
        if (!System.IO.File.Exists(path))
            throw new ArgumentException(String.Format("path \"{0}\" does not exist", path));
    }
}

然后像这样使用:

//Create the loader (a proxy).
var assemblyLoader =  (SimpleAssemblyLoader)myDomain.CreateInstanceAndUnwrap(typeof(SimpleAssemblyLoader).Assembly.FullName, typeof(SimpleAssemblyLoader).FullName);
//Load an assembly in the LoadFrom context. Note that the Load context will
//not work unless you correctly set the AppDomain base-dir and private-bin-paths.
assemblyLoader.LoadFrom(pathToExe);

//Do whatever you want to do.

//Finally unload the AppDomain.
AppDomain.Unload(myDomain);

你好,我刚刚尝试使用你的建议来预加载一些 .net 程序集,以查找它们是否包含某个接口类实现。但与将程序集加载到当前域相反,这个方法可以正常工作,但我无法将它们加载到我新创建的 AppDomain myDomain 中。 - Wolfgang Roth

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