Answered by:
Assembly.LoadFrom() & appDomains

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 Snippetusing
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 doaminobjGenerator.LoadDll(filename);
//Unlload domain AppDomain.Unload(myDomain);}
//end new assembly}
//end class}
//end namespaceCode Snippetusing
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{
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 namespaceSaturday, May 12, 2007 1:31 PM -
Hi stokiemike,
You can load the assembly by physical path and unload the AppDomain like this:
Code Snippetstatic 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 SnippetAppDomain.Unload("newDomain");
Also, I will suggest you load and create instance using AppDomain.
Code SnippetAppDomain.CreateInstance
AppDomain.Load
Let me know if you have diificulties :-)
Wednesday, May 9, 2007 12:43 AM -
Thanks Vic,
I have tried using
Code SnippetAppDomain.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 SnippetAssembly.LoadFromUnfortuantly, I can not load this into a seperate Application Domain. If I could them I could use the
Code SnippetAppDomain.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 Snippetpublic 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 SnippetAppDomain 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 MyClassHope 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 Snippetstatic 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 Snippetusing
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 doaminobjGenerator.LoadDll(filename);
//Unlload domain AppDomain.Unload(myDomain);}
//end new assembly}
//end class}
//end namespaceCode Snippetusing
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{
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 namespaceSaturday, 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