Article Options
Premium Sponsor
Premium Sponsor

 »  Home  »  .NET Framework  »  Sharing libraries without placing them to the GAC
Sharing libraries without placing them to the GAC
by Gaidar Magdanurov | Published  07/30/2006 | .NET Framework | Rating:
Gaidar Magdanurov
Gaidar Magdanurov is the editor-in-chief of VBStreets (www.vbstreets.ru) - Russian web site dedicated to Microsoft Visual Basic. He is also a Microsoft MVP and member of Russian Speakers Bureau, the founder and the leader of VBStreets .NET User Group, active member of Russian GotDotNet community and author of dozen of articles and. Gaidar has wide expirience in Web and Windows development and likes to share his knowledge. 

View all articles by Gaidar Magdanurov...
How To
When to use this approach

   You may want to use this when, for example, you want to keep a few libraries with some business logic on a remote file server on the network and  have the ability to easily update these libraries without sending their copies to all users of an application.     Or Maybe you may want to share a few libraries between several applications on a computer to quickly update the libraries in one place, but you can not use GAC for some reason.

How to implement

Every time the .NET runtime cannot find the necessary library in an application directory or GAC it raises a special event - AssemblyResolve - of the Application object.    A developer can subscribe to this event to implement custom logic.

The first step is to place the libraries in a special directory and make the path to this directory available to every application which is using shared libraries from this directory. The most obvious way is to store the path to the directory in the Windows Registry. For example:

[HKEY_CURRENT_USER\SimpleSharedLib]
"SharedPath"="C:\\Program Files\\My Shared Libraries"

The second step is to implement the AssemblyResolve event handler in every application that is using shared assemblies. It is important to add a handler for AssemblyResolve before any shared library will be used or you will get an Exception.

You can subscribe to the event in the handler of the Load event of the startup form or at the beginning of the Main procedure.

C#
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
VB.NET
AddHandler (AppDomain.CurrentDomain.AssemblyResolve), AddressOf CurrentDomain_AssemblyResolve

The handler of the AssemblyResolve event should find the path to the required assembly, check for the assembly existence and load the assembly via the LoadAssembly function.

C#
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string[] asmName = args.Name.Split(',');
    string sharedPath = Registry.GetValue("HKEY_CURRENT_USER\\SimpleSharedLib", 
                                        "SharedPath", String.Empty).ToString();
    if(sharedPath == String.Empty) throw(new Exception("Path to shared libraries not found."));
    string asmPath = Path.Combine(sharedPath, asmName[0] + ".dll");
    if (!File.Exists(asmPath)) throw (new Exception("Assembly " + asmName[0] + " not found."));
   return Assembly.LoadFile(asmPath, Assembly.GetExecutingAssembly().Evidence);
}
VB.NET
Public Shared Function CurrentDomain_AssemblyResolve(ByVal sender As Object, _
                 ByVal args As ResolveEventArgs) As System.Reflection.Assembly
    Dim asmName As String(), asmPath As String, sharedPath As String
    asmName = args.Name.Split(",")
    sharedPath = Registry.GetValue("HKEY_CURRENT_USER\\SimpleSharedLib", _
                                         "SharedPath", String.Empty).ToString()
    If sharedPath = String.Empty Then Throw (New Exception("Path to shared libraies not found."))
    asmPath = Path.Combine(sharedPath, asmName(0) & ".dll")
    If Not File.Exists(asmPath) Then Throw (New Exception("Assembly not found."))
    Return Assembly.LoadFile(asmPath, Assembly.GetExecutingAssembly().Evidence)
End Function

This code gets path to the directory containing shared libraries, the name of the assembly that the runtime is looking for.    If the assembly file exists, the code loads the assembly. It is noteworthy that the assembly is loaded with the same security settings as executing application because of the second parameter of Assembly.LoadFile function.

Avoiding access problems

There is a problem with the code shown above  if it is necessary to update a shared assembly file during execution of at least one application using the assembly.   This is because the runtime locks loaded assemblies. To avoid this you can read the assembly file to a byte array and use an overload of  the Load method that accepts an array of bytes.

C#
byte[] asm = File.ReadAllBytes(asmPath);
return Assembly.Load(asm);
VB.NET
asm = File.ReadAllBytes(asmPath)
Return Assembly.Load(asm)

Summary

You can develop and test as usual – create a reference to the required assembly and work with the library as you usually do. The event handler will do its job when you place your application in the production environment where will be no shared libraries in the application directory and the AssemblyResolve event will be raised by the runtime every time it cannot find an assembly. A working example is attached to this article.

How would you rate the quality of this article?
1 2 3 4 5
Poor Excellent
Tell us why you rated this way (optional):

Article Rating
The average rating is: No-one else has rated this article yet.

Article rating:4.17142857142855 out of 5
 35 people have rated this page
Article Score19681
Sponsored Links