The information in the manifest enables reliable determination of the identity and version of an assembly. This is the basis for the deployment options available in .NET, and for the side-by-side execution of assemblies that helps .NET overcome DLL hell. This section looks at these issues in detail.
It was mentioned earlier that assemblies can be of two types. The first is an application-private assembly. As the name implies, this type of assembly is used by one application only and is not shared. This is the default style of assembly in .NET and is the main mechanism by which an application can be independent of changes to the system.
Application-private assemblies are deployed into the application’s own directory. Because application-private assemblies are not shared, they do not need a strong name. This means that, at a minimum, they only need to have a name and version number in the identity section of the manifest. Because the assemblies are private to the application, the application does not perform version checks on the assemblies, as the application developer has control over the assemblies that are deployed to the application directory. If strong names exist, however, the CLR will verify that they match.
If all the assemblies that an application uses are application-private and the CLR is already installed on the target machine, then deployment is quite simple. Chapter 22 discusses this implication in more detail.
The second type of assembly is the shared assembly. As the name suggests, this type of assembly can be shared among several different applications that reside on the same server. This type of assembly should only be used when it is important to share assemblies among many applications. For example, a Windows Forms control purchased as part of a package may be used in many of your applications, and thus it is better to install a shared version of the assembly rather than copies of it for each application. The .NET Framework assemblies themselves are also examples of shared assemblies.
Certain requirements are placed upon shared assemblies. The assembly needs to have a globally unique name, which is not a requirement of application-private assemblies. As mentioned earlier, a strong name is used to create a globally unique name for an assembly. As the assembly is shared, all references to the shared assembly are checked to ensure that the correct version is being used by an application.
Shared assemblies are stored in the global assembly cache (GAC), which is usually located in the assembly folder in the Windows directory (for example, in Windows XP, C:\Windows\Assembly). However, it’s not enough to just copy an assembly into that directory. The process for placing an assembly in the GAC is similar in concept to registering a COM DLL. That process is discussed in detail later.
No other changes to the code of the assembly are necessary to differentiate it from that of an application-private assembly. In fact, just because an assembly has a strong name does not mean that it has to be deployed as a shared assembly; it could just as easily be deployed in the application directory as an application-private assembly.
Installing a shared assembly into the GAC requires administrator rights on the machine. This is another factor complicating deployment of shared assemblies. Because of the extra effort involved in the creation and deployment of shared assemblies, you should avoid this type of assembly unless you really need it.
Each computer that has the .NET runtime installed has a GAC. However, assemblies in the GAC are always stored in the same folder, no matter which version of .NET you have. The folder is a subfolder of your main Windows folder, and it is named Assembly. If you have multiple versions of the .NET Framework, assemblies in the GAC for all of them are stored in this directory.
As previously noted, a strong name is required for an assembly placed in that GAC. That strong name is used to identify a particular assembly. However, another piece of metadata is also used for verification of an assembly. When an assembly is created, a hash of the assembly is placed in the metadata. If an assembly is changed (with a binary editor, for example), the hash of the assembly will no longer match the hash in the metadata. The metadata hash is checked against the actual hash when an assembly is placed in the GAC with the gacutil.exe utility (described later). If the two hash codes do not match, the installation cannot be completed.
The strong name is also used when an application resolves a reference to an external assembly. It checks whether the public key stored in the assembly is equal to the hash of the public key stored as part of the reference in the application. If the two do not match, then the application knows that the external assembly has not been created by the original author of the assembly.
You can view the assemblies contained within the GAC by navigating to the directory using the Windows Explorer.
The gacutil.exe utility that ships with .NET is used to add and remove assemblies from the GAC. To add an assembly into the GAC using the gacutil.exe tool, use the following command line:
gacutil.exe /i myassembly.dll
Recall that the assembly being loaded must have a strong name.
To remove an assembly, use the /u option, like this:
gacutil.exe /u myassembly.dll
gacutil.exe has a number of other options. You can examine them and see examples of their usage by typing in the following command:
gacutil.exe /?