17.7 Private Assemblies
Assemblies come in two flavors: private and shared . Private assemblies are intended to be used by only one application; shared assemblies are intended to be shared among many applications.
All the assemblies you've built so far are private. By default, when you compile a C# application, a private assembly is created. The files for a private assembly are all kept in the same folder (or in a tree of subfolders). This tree of folders is isolated from the rest of the system, as nothing other than the one application depends on it, and you can redeploy this application to another machine just by copying the folder and its
A private assembly can have any name you choose. It does not matter if that
In the past, DLLs were installed on a machine and an entry was made in the Windows Registry. It was difficult to avoid corrupting the Registry, and reinstalling the program on another machine was nontrivial. With assemblies, all of that goes away. With private assemblies, installing is as simple as copying the files to the appropriate directory. Period.
17.8 Shared Assemblies
You can create assemblies that can be shared by other applications. You might want to do this if you have written a generic control or a class that might be used by other developers. If you want to share your assembly, it must meet certain stringent requirements.
First, your assembly must have a
Second, your shared assembly must be protected against
Finally, to share your assembly, place it in the Global Assembly Cache (GAC) (pronounced GACK). This is an area of the filesystem set aside by the CLR to hold shared assemblies.
17.8.1 The End of DLL Hell
Assemblies mark the end of DLL Hell. Remember this scenario: you install Application A on your machine, and it loads a number of DLLs into your Windows directory. It works great for months. You then install Application B on your machine, and suddenly, unexpectedly, Application A breaks. Application B is in no way
When DLLs were invented, disk space was at a premium and reusing DLLs seemed like a good idea. The theory was that DLLs would be
When the new DLL was added to the computer, the old application, which was happily minding its own business in another corner of your machine, suddenly linked to a DLL that was incompatible with its expectations and hey! Presto! It went into the
Shared assemblies in .NET are uniquely identified by their names and their versions. The GAC allows for "side-by-side" versions in which an older version of an assembly is available
A version number for an assembly might look like this:
(four numbers, separated by colons). The first two
When two assemblies have different major or minor numbers, they are considered to be incompatible. When they have different build numbers, they might or might not be compatible, and when they have different revision numbers, they are
Revision numbers are intended for bug fixes. If you fix a bug and are prepared to
17.8.3 Strong Names
In order to use a shared assembly, you must meet three requirements:
All these requirements are met by strong names. Strong names must be globally unique and use public key encryption to ensure that the assembly hasn't been tampered with and was written by the creator. A strong name is a string of hexadecimal digits and is not
To create a strong name, a
When an application loads the assembly, the CLR uses the public key to decode the hash of the files in the assembly to ensure that they have not been tampered with. This also protects against name
You can create a strong name with the sn utility:
sn -k c:\myStrongName.snk
The -k flag indicates that you want a new key pair written to the specified file. You can call the file anything you like. Remember, a strong name is a string of hexadecimal digits and is not meant to be human-readable.
You can associate this strong name with your assembly by using an attribute:
using System.Runtime.CompilerServices; [assembly: AssemblyKeyFile("c:\myStrongName.key")]
Attributes are covered in detail in Chapter 18. For now, you can just put this code at the top of your file to associate the strong name you generated with your assembly.
17.8.4 The Global Assembly Cache
Once you've created your strong name and associated it with your assembly, all that remains is to place the assembly in the GAC, which is a reserved system directory. You can do that with the gacutil utility:
gacutil /i MySharedAssembly.dll
Or you can open your File Explorer and drag your assembly into the GAC. To see the GAC,
17.8.5 Building a Shared Assembly
The best way to understand shared assemblies is to build one. Let's return to the earlier multi-module project (see Examples Example 17-1 through Example 17-4) and navigate to the directory that contains the files Calc.cs and Fraction.cs .
Try this experiment: locate the bin directory for the driver program and make sure that you do not have a local copy of the MySharedAssembly DLL files.
Run the program. It should fail with an exception saying it cannot load the assembly:
Unhandled Exception: System.IO.FileNotFoundException: File or assembly name MySharedAssembly, or one of its dependencies, was not found. File name: "MySharedAssembly" at Programming_CSharp.Test.UseCS( ) at Programming_CSharp.Test.Main( )
Now copy the DLLs into the driver program's directory tree, run it again, and this time you should find that it works fine.
Let's make the MySharedAssembly into a shared assembly. This is done in two steps. First, create a strong name for the assembly, and then you put the assembly into the GAC.
220.127.116.11 Step 1: Create a strong name
Create a key pair by opening a command window and entering:
sn -k keyFile.snk
Now open the AssemblyInfo.cs file in the project for the MySharedAssembly.dll and modify this line:
This sets the key file for the assembly. Rebuild with the same makefile as earlier, and then open the resulting DLL in ILDasm and open the manifest. You should see a public key, as shown in Figure 17-8.
Figure 17-8. The originator in the manifest of MySharedAssembly.dll
By adding the strong name, you have signed this assembly (your exact values will be different). You now need to get the strong name from the DLL. To do this, navigate to the directory with the DLL and enter the following at a command prompt:
sn -T MySharedAssembly.dll
The response should be something like this:
Public key token is 01fad8e0f0941a4d
This value is an abbreviated version of the assembly's public key, called the public key token .
Remove the DLLs from the test program's directory structure and run it again. It should fail again. Although you've given this assembly a strong name, you've not yet registered it in the GAC.
18.104.22.168 Step 2: Put the shared assembly in the GAC
You can drag-and-drop into the GAC viewer, or you can invoke this command-line utility:
gacutil /i MySharedAssembly.dll
In either case, be sure to check that your assembly was loaded into the GAC, and that the originator value shown in the GAC viewer matches the value you got back from sn :
Public key token is 01fad8e0f0941a4d
Figure 17-9. The GAC
Once this is done, you have a shared assembly that can be accessed by any client. Refresh the client by building it again and look at its manifest, as shown in Figure 17-10.
Figure 17-10. The manifest
There's MySharedAssembly , listed as an external assembly, and the public key now matches the value shown in the GAC. Very nice, time to try it.
and compile and run your code. It should work fine, even though there are no DLLs for this library in its immediate