Dynamically loading and Unloading Assemblies in C#
While working on a plugin manager for a program written in C#, I found myself with a need to be able to load and unload assemblies dynamically be an application. In C#, loading assemblies is a fairly easy prospect — one just needs to make use of the System.Reflection class. Something like the following:
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFile(@"c:\yourassembly.dll");
However, if you need to unload the assembly — good luck. The .NET assembly class doesn’t include an unload method. If you have a need to be able to dynamically load an unload assemblies, you need to work with the AppDomain class. The .NET framework works on an Application Domain model, so for items like plugins (where you may need to load, unload or modify an assembly), you need to create an Application Domain manager to load assemblies onto. This way, when you need to unload an assembly, you use the Unload method found within the AppDomain class.
Of course, when dealing with plugins, you likely will need to create a new application domain for each plugin to be loaded. This is because the you unload the appdomain, not the assemblies attached to the domains. So for my project, I decided to create something much like the TempFileCollection. In a global class, I decided to create a hash that stories a domain name and the domain object. Using this method, I can do something like the following:
1: string path = cglobal.mglobal.AppPath() + "plugins" + System.IO.Path.DirectorySeparatorChar;
2: string[] files = System.IO.Directory.GetFiles(path);
3:
4: lstInstalled.Items.Clear();
5: foreach (string f in files)
6: {
7: try
8: {
9: System.AppDomain domain = System.AppDomain.CreateDomain(System.IO.Path.GetFileName(f));
10: System.IO.StreamReader reader = new System.IO.StreamReader(f, System.Text.Encoding.GetEncoding(1252), false);
11:
12: byte[] b = new byte[reader.BaseStream.Length];
13: reader.BaseStream.Read(b, 0, System.Convert.ToInt32(reader.BaseStream.Length));
14:
15: domain.Load(b);
16: System.Reflection.Assembly[] a = domain.GetAssemblies();
17: int index = 0;
18:
19:
20:
21:
22: for (int x = 0; x < a.Length; x++)
23: {
24: if (a[x].GetName().Name + ".dll" == System.IO.Path.GetFileName(f))
25: {
26: index = x;
27: break;
28: }
29: }
30:
31: System.Windows.Forms.ListViewItem item = new ListViewItem();
32:
33: item.Text = a[index].GetName().Name + ".dll";
34: item.SubItems.Add(a[index].GetName().Version.ToString());
35: item.SubItems.Add(reader.BaseStream.Length.ToString());
36: lstInstalled.Items.Add(item);
37: reader.Close();
38: cglobal.mglobal.domains.Add(System.IO.Path.GetFileName(f), domain);
39:
40: }
41: catch { }
42: }
Then, if we need to unload the assembly, we can unload the domain that its attached to. Something like:
1: for (int x = 0; x < lstInstalled.Items.Count; x++)
2: {
3: if (lstInstalled.Items[x].Selected == true) {
4: try {
5: if (System.IO.File.Exists(cglobal.mglobal.AppPath() + "plugins" + System.IO.Path.DirectorySeparatorChar + lstInstalled.Items[x].Text)) {
6: System.AppDomain.Unload((System.AppDomain)cglobal.mglobal.domains[lstInstalled.Items[x].Text]);
7: cglobal.mglobal.domains.Remove(lstInstalled.Items[x].Text);
8: System.IO.File.Delete(cglobal.mglobal.AppPath() + "plugins" + System.IO.Path.DirectorySeparatorChar + lstInstalled.Items[x].Text);
9: }
10: }
11: catch {}
12: }
13: }
Seems a little more involved that it has to be, but once you know how it works, its not that big of a deal.
–TR
3 Comments to Dynamically loading and Unloading Assemblies in C#
Leave a comment
Categories
- Access 2006
- ALA Midwinter 2007
- ALA Summer 2007
- Book
- C#
- Code4Lib 2007
- Code4Lib2008
- Conferences
- CONTENTdm
- Cycling
- Digital Libraries
- Dspace
- Education
- Family
- General Computing
- Innovative Interfaces
- Java
- LibraryFind
- MarcEdit
- Microsoft
- NWIUG 2006
- OAI
- OCLC
- Open Library
- OSCON 2006
- Patent Stupidity
- Programming
- rails
- Readex 2006
- ruby
- Running
- Simpsons
- Travel
- Uncategorized
- Wii
- Wikipedia
Archive
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
- August 2006
- July 2006
- June 2006
- May 2006
- April 2006
- March 2006
- February 2006
- January 2006
- December 2005
- November 2005
- October 2005
- September 2005
- August 2005
- July 2005
[...] the Plugin manager. Was a little more involved than I thought it would be (see: Dynamically loading/unloading Assemblies in C#), but it looks like the loading and unloading of assemblies is working like I want it to. No [...]
thanks for the GREAT post! Very useful…
thanks for code.very useful