Shared Assemblies

Assemblies frequently reference other assemblies. Recall from the previous chapter that the references can be specified either by using -r switch on the C# compiler or by using a response file.

An assembly can execute only if the assembly resolver is able to locate the referenced assemblies. One way to ensure this is to deploy all the referenced assemblies in the same directory as that of the main application or a subdirectory under the application's directory, as we saw in the previous chapter. In this case, the referenced assemblies are called private assemblies as they are “private” to the application using them.

Private assemblies are good if there is only one application consuming them, and they are preferred. There are times, however, when you wish to share an assembly with multiple applications. A good example of such a shared assembly is MsCorLib.dll; it is used by multiple applications. Shared assemblies are typically created by one company and used by other companies.

Obviously, a shared assembly has to be installed in a common place such that it is accessible to other applications. Under .NET, this shared area is called the Global Assembly Cache (GAC).

The GAC is present on each machine that has the .NET Framework installed and acts as a machine-wide code cache. It is located in the <windir>assembly subdirectory where <windir> is the Windows directory (e.g., C:Windows).

A region of the GAC is used to store assemblies downloaded over the Internet or intranet. This region is called the download cache. There is one download cache per user.

To add an assembly to the GAC, the .NET Framework provides a utility called the GAC tool (gacutil.exe). To add ConsoleGreeting.dll from our previous chapter to the GAC, for example, the following command line can be used:

gacutil.exe –i ConsoleGreeting.dll

Switch -i indicates that the specified assembly should be added to the GAC. For a multifile assembly, the prime module (the module containing the assembly's manifest) must be specified as the parameter.

Note that you need administrative privileges to install an assembly in the GAC.

Choose Your Installer Wisely

XCOPY installation works very well for simple applications that use just the private assemblies. However, the mechanism is not suitable if you wish to install assemblies into the GAC or perform some special operations, such as running an assembly as a service.

On a customer's machine, the preferred way of installing assemblies in the GAC is by using an installer that is designed to work with the GAC. Windows Installer 2.0 is one such installer.


Table 3.2 lists important switches on the GAC tool. Check the SDK documentation for a complete list.

Table 3.2. GAC Tool Switches
SwitchDescription
-lList assemblies in the GAC
-uUninstall an assembly from the GAC
-ldlList assemblies in the download cache for the current user
-cdlClear the download cache for the current user

There is one more way to view and manipulate the contents of the GAC, using the Windows Explorer. The .NET Framework provides a Windows shell extension called the Assembly Cache Viewer (shfusion.dll) for this purpose. For example, to view the contents of the GAC, you just have to navigate to the <windir>assembly subdirectory from Windows Explorer. A snapshot of the GAC from the viewer is shown in Figure 3.2.

Figure 3.2. Global Assembly Cache.


To add an assembly to the GAC, you can just drag and drop the assembly file to this directory. To delete an assembly, select its name in the Explorer and press delete.

Note that the download cache for the current user can be found under <windir>assemblyDownload subdirectory.

Viewing Raw GAC

When the assembly is installed in the GAC, a unique subdirectory is created and all the files of the assembly are copied into the subdirectory. You cannot see this subdirectory from Windows Explorer (because of the Window shell extension). However, you can open a console window and navigate to the GAC directory to see its contents in raw form.


There is an important security issue to be considered when installing shared assemblies. As a shared assembly can potentially be used by many applications, it is important to ensure that the assembly is not tampered with after it is created. By maliciously tampering the assembly, a hacker can cause substantial damage, especially if the assembly gets executed in a privileged account. Therefore, .NET mandates that only strong-named assemblies can be installed in the GAC.

Earlier, I mentioned that to load an assembly programmatically, only the filename field of its identity is a must, the other fields are optional. However, the preferred way to load an assembly from the GAC is to provide a full reference (e.g., the complete identity string), as illustrated in the following code. Here, we are trying to load a runtime installed assembly, System.Windows.Forms, from the GAC:

// Project LoadAssembly

name = @"System.Windows.Forms, Version=1.0.3300.0,
  Culture=neutral, PublicKeyToken=b77a5c561934e089";
Assembly e = Assembly.Load(name);
Console.WriteLine(e.FullName);

For partial references, method Assembly.Load does not even bother to look into the GAC. The only exception to this is the assembly MsCorLib.dll, which does not require a full reference. The assembly resolver gives special treatment to this assembly and lets you locate it with just the name field of the identification.

If you wish the assembly resolver to consider looking into the GAC as well as application-specific directories, then you can use another method, Assembly.LoadWithPartialName, as shown in the following example:

// Load with partial reference from the GAC
name = @"System.Windows.Forms";
Assembly a6 = Assembly.LoadWithPartialName(name);
Console.WriteLine(a6.FullName);

The End of DLL Hell

Windows users have probably experienced the problem of installing a new application that suddenly breaks some other previously installed application(s) on the machine. This usually happens when the applications share a DLL and the newer version of the DLL is not compatible with previously installed applications. This problem is referred to as DLL hell.

.NET eliminates this DLL hell problem once and for all. The crux of the DLL hell problem is that the newer version of the DLL replaced the existing version of the DLL, but this newer version is not fully compatible with previously installed applications, thus breaking those applications.

.NET makes it possible for multiple versions of a shared assembly to coexist on the same machine. To install a newer version of an assembly, just add it to the GAC. The GAC will store the older and newer versions. From GAC's point of view, these are two different assemblies, as their strong names do not match (because of the version number). As a matter of fact, as the GAC indexes an assembly by the strong name, it is entirely possible to have two assemblies with the same name, public key, and version, but different culture settings.

We already know that when an application is executed, for each strong-named assembly the application references, the assembly resolver tries to bind with the exact version of the assembly that the application was built with. As a result, if a newer version of a shared assembly is installed on the machine, the previous installed application can continue to use the older version of the assembly, effectively eliminating the DLL hell problem.

Although the default behavior of the runtime is to find an exact match on the version number of the strong-named assemblies, it is possible to customize this behavior by means of configuration files. This gives the administrators a chance to use the older applications with the newer version of the shared assemblies and, if things don't work as expected, revert back to the older version.

Let's see how the assembly binding behavior can be customized using the configuration files.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.147.87