سؤال

I'm met with a big problem in C# AppDomain.

I need to load a static class in a .dll file and execute its method:

  1. When I try to load them by

    Assembly.LoadFrom("XXXXX") // (XXXXX is the full path of dll)
    

    the .dll will not be unload automatically or programmatically.

  2. When I try to load them in AppDomain like

    adapterDomain = AppDomain.CreateDomain("AdapterDomain");
    (a)adapterDomain.CreateInstanceFrom(this.AdapterFilePath, this.AdapterFullName);
    (b)adapterAssembly=adapterDomain.Load(AssemblyName.GetAssemblyName(this.AdapterFilePath));
    

    If I use method (a), because the target class is a static one, it doesn't work.

    If I use method (b), because the target .dll is not the same directory with my project, I will get an exception.

How can I load the .dll and the static class, and then unload the .dll after my usage?

هل كانت مفيدة؟

المحلول

Method (b) fails because AppDomain.Load cannot resolve assemblies that are not in the base app dir, the probing private paths or the GAC.

Also note that the AppDomain.Load is not loading the assembly on the specific AppDomain (like adapterDomain.Load in your sample code). Instead it is loading it on the current AppDomain (this is the one making the call to AppDomain.Load. This behavior is remarked on the MSDN documentation.) Apparently this is not what you are looking for.

Here's an example on how to call a static method in the child AppDomain:

class Program
{
    static void Main(string[] args)
    {
        // This is for testing purposes!
        var loadedAssembliesBefore = AppDomain.CurrentDomain.GetAssemblies();

        var domain = AppDomain.CreateDomain("ChildDomain");                        
        // This will make the call to the static method in the dhild AppDomain.
        domain.DoCallBack(LoadAssemblyAndCallStaticMethod);
        // Print the loaded assemblies on the child AppDomain. This is for testing purposes!
        domain.DoCallBack(PrintLoadedAssemblies);
        AppDomain.Unload(domain);

        // This is for testing purposes!
        var loadedAssembliesAfter = AppDomain.CurrentDomain.GetAssemblies();
        // Assert that no assembly was leaked to the main AppDomain.
        Debug.Assert(!loadedAssembliesBefore.Except(loadedAssembliesAfter).Any());

        Console.ReadKey();
    }

    // Loads StaticMethodInHere.dll to the current AppDomain and calls static method 
    // StaticClass.DoSomething.  
    static void LoadAssemblyAndCallStaticMethod()
    {
        var assembly = Assembly.LoadFrom(@"PATH_TO_ASSEMBLY");

        assembly.GetType("CLASS_CONTAINING_STATIC_METHOD")
                .InvokeMember("STATIC_METHOD", 
                              BindingFlags.Public | 
                              BindingFlags.Static | 
                              BindingFlags.InvokeMethod, 
                              null, 
                              null, 
                              null);
    }

    // Prints the loaded assebmlies in the current AppDomain. For testing purposes.
    static void PrintLoadedAssemblies()
    {
        Console.WriteLine("/ Assemblies in {0} -------------------------------",
                          AppDomain.CurrentDomain.FriendlyName);

        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            Console.WriteLine(assembly.FullName);
        }            
    }
}

To make this work you will need to replace:

  • PATH_TO_ASSEMBLY with the path of the assembly containing the static method including the extension.
  • CLASS_CONTAINING_STATIC_METHOD with the name of the class containing the static method including the namespace of the class.
  • STATIC_METHOD with the name of the static method.

Note that the BindingFlags are set for public static methods.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top