Create custom AppDomain and add assemblies to it
Asked Answered
F

1

9

How can I create an appdomain, add assemblies to it, then destroy that app domain? This is what I have tried:

    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!            
    }

I have also tried:

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

how can I add an assembly to the appdomain. Once I do that I can find the method via reflection execute it and then destroy the appdomain

The exception that I get is:

Could not load file or assembly 'ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

Florinda answered 20/6, 2013 at 23:4 Comment(2)
It is easier to load assembly to your own domain - so instead of trying to push assembly into other domain consider running some code in other domain to load whatever assembly you want (don't forget that you may need to pre-load dependencies or setup assembly search path correctly).Microcrystalline
"Or one of its dependencies" is the usual problem. Use Fuslogvw.exe if you have no idea what that might be. And use AppDomainSetup to set the correct private path.Division
G
11

Two quick points:

  1. AppDomain.Load loads an assembly in the current AppDomain and not on myDomain (weird, I know).
  2. AppDomain.Load loads an assembly in the Load context, which resolves assemblies from the apps base-dir, the private-bin-paths and the GAC. Most probably, the assembly you try to load is not located in any of these locations which explains the exception message.

For more info have a look at this answer.

One way to load assemblies to an AppDomain is by creating a MarshalByRef-derived loader. You need something like this to avoid leaking types (and assemblies) to your main AppDomain. Here's a simple one:

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));
    }
}

And use it like that:

//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);
Gaudette answered 26/6, 2013 at 15:19 Comment(1)
Hello, I just tried to use your suggestion to kind of preload some .net assemblys to find out if they contain a certain interface class implementation. But in contrast to loading the assembly into the current domain, which works fine, i cannot load them into my newly created AppDomain myDomain.Additory

© 2022 - 2024 — McMap. All rights reserved.