none
Assembly.LoadFrom() & appDomains RRS feed

  • Question

  • I need to unload my loaded assembly. I have used LoadFrom to give me the flexability of loading the dll from any location.

    However, to totally remove the assembly I need to unload the AppDomain, but I don't know how to initialy load the assembly into the AppDomain.

     

     

    AppDomain newDomain = AppDomain.CreateDomain("newDomain", null, domainSetup);

    assembly a = Assembly.LoadFrom(filename);

    foreach (Type TypeAlgorithm in a.GetExportedTypes())
    {
         if (TypeAlgorithm.IsClass == true)
         {
              ObjAlgorithmInstance = Activator.CreateInstance(TypeAlgorithm);
              methodInfo = ObjAlgorithmInstance.GetType().GetMethod("start");
              methodInfo.Invoke(ObjAlgorithmInstance, new object[] { });
         }
    }

    //NEED TO UNLOAD THE ASSEMBLY, BUT HOW???

    Tuesday, May 8, 2007 8:55 PM

Answers

  • Thanks Vic, your a star. It works perfectly.

     

    I have included the code below for anybody else to view. Hope it helps others in the future!!!!

     

     

     

    Code Snippet

    using System;

    using System.IO;

    using System.Reflection;

    using System.Reflection.Emit;

    using Daedalus.AssemblyLoader;

    namespace Daedalus.AssemblyLoader

    {

    public class ClassLoader

    {

    public static void NewAssembly(String filename)

    {

    // Create application domain setup information.

    AppDomainSetup domainSetup = new AppDomainSetup();

    domainSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

    domainSetup.ApplicationName = "Algorithms";

    //Create new domain with domain setup details

    AppDomain myDomain = AppDomain.CreateDomain("LoaderDomain", null, domainSetup);

    //Create new instance of Loader class, where the dll is loaded.

    //This is loaded into the new application domian so it can be

    //unloaded later

    Loader objGenerator = (Loader)myDomain.CreateInstanceAndUnwrap(

    Assembly.GetExecutingAssembly().FullName, "Daedalus.AssemblyLoader.Loader");

    //Call LoadDll method to load the assembly into the doamin

    objGenerator.LoadDll(filename);

    //Unlload domain

    AppDomain.Unload(myDomain);

    }//end new assembly

    }//end class

    }//end namespace

     

    Code Snippet

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Reflection;

    using System.IO;

    namespace Daedalus.AssemblyLoader

    {

    [Serializable]

    class Loader

    {

    public void LoadDll(string filename)

    {

    if (File.Exists(filename))

    {

    //Loads file into Bytle array - prevent file locking

    byte[] rawAssembly = loadFile(filename);

    //algorithmAssembly = Assembly.LoadFrom(filename);

    Assembly algorithmAssembly = Assembly.Load(rawAssembly);

    foreach (Type TypeAlgorithm in algorithmAssembly.GetExportedTypes())

    {

    if (TypeAlgorithm.IsClass == true)

    {

    Console.WriteLine("Type is {0}", TypeAlgorithm);

    Object ObjAlgorithmInstance = Activator.CreateInstance(TypeAlgorithm);

    //Invoke method - start() within the dll

    MethodInfo methodInfo = ObjAlgorithmInstance.GetType().GetMethod("start");

    methodInfo.Invoke(ObjAlgorithmInstance, new object[] { });

    }

    }

    }

    }//End DoadDll

     

    // Loads the content of a file to a byte array.

    //Prevent file locking, so user can modify dll

    //while using the dll

    static byte[] loadFile(string filename)

    {

    FileStream fs = new FileStream(filename, FileMode.Open);

    byte[] buffer = new byte[(int)fs.Length];

    fs.Read(buffer, 0, buffer.Length);

    fs.Close();

    return buffer;

    }//End loadFile

    } //End class

    }//End namespace

     

    Saturday, May 12, 2007 1:31 PM
  • Hi stokiemike,

       You can load the assembly by physical path and unload the AppDomain like this:

    Code Snippet

         static void AppDomainTest ( )
            {
                // Assembly you want to load
                String fileName = @"D:\Test\TestClass.dll";
                String AsmName = @"TestClass";
                FileInfo fi = new FileInfo( fileName );
                String fileDir = fi.DirectoryName;

               

              // Setup the evidence
                Evidence evidence = new Evidence( AppDomain.CurrentDomain.Evidence );
                AppDomain TestDomain = AppDomain.CreateDomain(
                    "TestDomain",             // The friendly name of the domain.
                    evidence,                     // Evidence mapped through the security policy to establish a top-of-stack permission set.
                    AppDomain.CurrentDomain.BaseDirectory,  // The base directory that the assembly resolver uses to probe for assemblies.
                    fileDir,              // The path relative to the base directory where the assembly resolver should probe for private assemblies.
                    true );                           // If true, a shadow copy of an assembly is loaded into this application domain.

            

              // Load the assembly

              TestDomain.Load( AsmName );    
                AppDomain.Unload( TestDomain );  // Unload the AppDomain
            }

     

     

     

    Hope it will help you.

    Thanks!

     

    Friday, May 11, 2007 6:10 AM

All replies

  • Hi,

    You are right, If you want to unload a assembly , then we have to use AppDomain.

    You can

    Code Snippet

    AppDomain.Unload("newDomain");

     

    Also, I will suggest you load and create instance using AppDomain.

    Code Snippet

    AppDomain.CreateInstance

    AppDomain.Load

     

     Let me know if you have diificulties :-)

    Wednesday, May 9, 2007 12:43 AM
  • Thanks Vic,

     

    I have tried using

     

    Code Snippet

    AppDomain.Load

     

    Before, but this restricts me to only loading dll's from the GAC or the application directory. I need to load dll's from anylocation on the computer, so I am forced to use the

    Code Snippet
    Assembly.LoadFrom

     

    Unfortuantly, I can not load this into a seperate Application Domain. If I could them I could use the

     

    Code Snippet

     AppDomain.Unload("newDomain");

     

    To unload the Domain. How do I use the Assembly.LoadFrom() with separate AppDomains??

     

    Any ideas??

     

    Thanks again

    Wednesday, May 9, 2007 8:00 AM
  • Have found a metod to load assembly into new domain. However, the dll file is locked and I cannot change its contence with the method os executing. I thought the ShadowCopyFile allows adjustments to assembly while its executing. Any suggestions

     

    Code Snippet

    public static void LoadAssembly(String filename)
    {
    // Create application domain setup information.
    AppDomainSetup domainSetup = new AppDomainSetup();
    domainSetup.ShadowCopyFiles = "true";

    //Create domain with setup parameters
    AppDomain myDomain = AppDomain.CreateDomain("Algorithm", null, domainSetup);


    //Create instance of class
    Object objAlgorithm = myDomain.CreateInstanceFromAndUnwrap(@"I:\temp\algorithmCS.dll", "Algorithms.algorithmCS");

    //Execute specific member of the class
    object[] arguments = new object[0];
    objAlgorithm.GetType().InvokeMember("start",
    BindingFlags.Default | BindingFlags.InvokeMethod,
    null,
    objAlgorithm, arguments);
    //Unload assembly
    AppDomain.Unload(myDomain);
    myDomain = null;
    objAlgorithm = null;
    }

     

     

    Wednesday, May 9, 2007 8:57 PM
  • Hi Mike,

    This is what I was trying to tell in first reply.... Actually Even I had this problem... I had to load a dll and unload it . There is two ways to do it ( as far as I know ) :

    1) Create a new process and load it ( very very bad way of doing it ). DLL will be loaded in its proces space

     2) Create AppDomain. What I did was something like below :

    Code Snippet
    AppDomain myDomain = AppDomain.CreateDomain("LoaderDomain");
                MyClass objGenerator = (MyClass)myDomain.CreateInstanceAndUnwrap("ClassDiagramGenerator", "ClassDiagramGenerator.MyClass");
    objGenerator.LoadMyDLL(strAssembly); 
         AppDomain.Unload(myDomain);

     

    In MyClass object, try loading a Assembly. For example write a method LoadDllAndComeBack .

    What do you mean by dll is locked?

    Do you mean it is loaded in memory and you are not able to delete it ( or modify ).

    ShadowCopyFiles should have hlped you out ( also remember to clear them ).

    I am able to load the dll and modify.

    Hope this helps........ :-)

    Wednesday, May 9, 2007 11:11 PM
  • Thanks ever so much for replying.

     

    Unfortunately I'm not that good programmer. Am a little confused what MyClass, LoadmyDLL and LoadDllAndComeBack is? Where have these come from? Sorry I’m properly been stupid!

     

    Have tried using CreateInstanceAndUnwrap with constant Seralizable errors and I have lost the ability to load from any directory on the computer.

     

    Just don't know what to do anymore have tried load of different methods!!

     

    Thursday, May 10, 2007 8:35 PM
  • Hi Mike,

    When I faced this problem, I thought I can't fix it. But I did it.

    Here in above code, MyClass is simple class in the same project ( or namespace ). It has method (LoadmyDLL ) which will load dll and send me the info required from dll. What I do is create a instance of MyClass in different Domain. Using the object , I call LoadMyDLL method. This will do required things. Then UnLoad the domain ( which will unload assembly loaded in that domain ).

    It will throw serializable error. For that MyClass should be ( Read this link - http://msdn2.microsoft.com/en-us/library/system.serializableattribute.aspx

    [Serializable]

    public class MyClass

    Hope this helps you.

      Regards

    Pavan 

    Friday, May 11, 2007 3:30 AM
  • Hi stokiemike,

       You can load the assembly by physical path and unload the AppDomain like this:

    Code Snippet

         static void AppDomainTest ( )
            {
                // Assembly you want to load
                String fileName = @"D:\Test\TestClass.dll";
                String AsmName = @"TestClass";
                FileInfo fi = new FileInfo( fileName );
                String fileDir = fi.DirectoryName;

               

              // Setup the evidence
                Evidence evidence = new Evidence( AppDomain.CurrentDomain.Evidence );
                AppDomain TestDomain = AppDomain.CreateDomain(
                    "TestDomain",             // The friendly name of the domain.
                    evidence,                     // Evidence mapped through the security policy to establish a top-of-stack permission set.
                    AppDomain.CurrentDomain.BaseDirectory,  // The base directory that the assembly resolver uses to probe for assemblies.
                    fileDir,              // The path relative to the base directory where the assembly resolver should probe for private assemblies.
                    true );                           // If true, a shadow copy of an assembly is loaded into this application domain.

            

              // Load the assembly

              TestDomain.Load( AsmName );    
                AppDomain.Unload( TestDomain );  // Unload the AppDomain
            }

     

     

     

    Hope it will help you.

    Thanks!

     

    Friday, May 11, 2007 6:10 AM
  • Looks like a very good way of doing it.... Even I will give a try when I am free.
    Friday, May 11, 2007 7:00 AM
  • Thanks guys for all your help. I'm seriously loosing sleep over this.

     

    I like the look of your code Feng, will try it when I get home. I presume that because the path is relative to the base directory of the application, then loading files from other drives or below the base directory is not allowed. Any ideas on this?

     

     Vic, thanks very much for explaining your code to me, I totally understand where your going. I now have two ideas to play with later - I can see light at the end of the tunnel!!!! Yeah!!!

     

    Will keep you posted!

     

    Thanks again guys!!!!!!

    Friday, May 11, 2007 10:23 AM
  • Thanks Vic, your a star. It works perfectly.

     

    I have included the code below for anybody else to view. Hope it helps others in the future!!!!

     

     

     

    Code Snippet

    using System;

    using System.IO;

    using System.Reflection;

    using System.Reflection.Emit;

    using Daedalus.AssemblyLoader;

    namespace Daedalus.AssemblyLoader

    {

    public class ClassLoader

    {

    public static void NewAssembly(String filename)

    {

    // Create application domain setup information.

    AppDomainSetup domainSetup = new AppDomainSetup();

    domainSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

    domainSetup.ApplicationName = "Algorithms";

    //Create new domain with domain setup details

    AppDomain myDomain = AppDomain.CreateDomain("LoaderDomain", null, domainSetup);

    //Create new instance of Loader class, where the dll is loaded.

    //This is loaded into the new application domian so it can be

    //unloaded later

    Loader objGenerator = (Loader)myDomain.CreateInstanceAndUnwrap(

    Assembly.GetExecutingAssembly().FullName, "Daedalus.AssemblyLoader.Loader");

    //Call LoadDll method to load the assembly into the doamin

    objGenerator.LoadDll(filename);

    //Unlload domain

    AppDomain.Unload(myDomain);

    }//end new assembly

    }//end class

    }//end namespace

     

    Code Snippet

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Reflection;

    using System.IO;

    namespace Daedalus.AssemblyLoader

    {

    [Serializable]

    class Loader

    {

    public void LoadDll(string filename)

    {

    if (File.Exists(filename))

    {

    //Loads file into Bytle array - prevent file locking

    byte[] rawAssembly = loadFile(filename);

    //algorithmAssembly = Assembly.LoadFrom(filename);

    Assembly algorithmAssembly = Assembly.Load(rawAssembly);

    foreach (Type TypeAlgorithm in algorithmAssembly.GetExportedTypes())

    {

    if (TypeAlgorithm.IsClass == true)

    {

    Console.WriteLine("Type is {0}", TypeAlgorithm);

    Object ObjAlgorithmInstance = Activator.CreateInstance(TypeAlgorithm);

    //Invoke method - start() within the dll

    MethodInfo methodInfo = ObjAlgorithmInstance.GetType().GetMethod("start");

    methodInfo.Invoke(ObjAlgorithmInstance, new object[] { });

    }

    }

    }

    }//End DoadDll

     

    // Loads the content of a file to a byte array.

    //Prevent file locking, so user can modify dll

    //while using the dll

    static byte[] loadFile(string filename)

    {

    FileStream fs = new FileStream(filename, FileMode.Open);

    byte[] buffer = new byte[(int)fs.Length];

    fs.Read(buffer, 0, buffer.Length);

    fs.Close();

    return buffer;

    }//End loadFile

    } //End class

    }//End namespace

     

    Saturday, May 12, 2007 1:31 PM
  • Nice one StokieMike, that works a treat.
    Thanks.


    http://learnerps-dotnet.blogspot.com/
    Friday, September 4, 2009 7:41 AM

  • Nice work Pavan... This asks for a couple of beers from you tonight ;)

    Regards,
    Samacumen..

    Friday, September 25, 2009 7:00 AM