Section 17.7. Shared Assemblies


17.7. 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 strong name. Strong names are globally unique.

No one else can generate the same strong name as you because an assembly generated with one private key is guaranteed to have a different name than any assembly generated with another private key.


Second, your shared assembly must be protected against newer versions trampling over it, and so each new version you release must have a new version number.

Finally, to share your assembly, place it in the Global Assembly Cache (GAC) (pronounced "gak"). This is an area of the filesystem set aside by the CLR to hold shared assemblies.

17.7.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 related to Application A. So what happened? It turns out, you later learn, that Application B replaced a DLL that Application A needed, and suddenly Application A began to stagger about, blind and senseless.

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 backward-compatible, so automatically upgrading to the new DLL would be painless and safe. As my old boss Pat Johnson used to say, "In theory, theory and practice are the same. But in practice, they never are."

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 dance of death. This phenomenon led customers to be justifiably leery of installing new software, or even of upgrading existing programs, and it is one of the reasons Windows machines are perceived to be unstable. With assemblies, this entire nightmare goes away.

17.7.2. Versions

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 alongside a newer version.

Side-by-side versioning applies only to items in the GAC. Private assemblies don't need this feature and don't have it.


A version number for an assembly might look like this: 1:0:2204:21 (four numbers, separated by colons). The first two numbers (1:0) are the major and minor versions. The third number (2204) is the build, and the fourth (21) is the revision.

When two assemblies have different major or minor numbers, they are considered by convention 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 considered definitely compatible with each other. This is great in theory, but the CLR assembly resolver ignores this convention and it serves only to remind the developer; it isn't enforced at runtime.

17.7.3. Strong Names

To use a shared assembly, you must meet two requirements:

  • You need to be able to specify the exact assembly you want to load.

  • You need to ensure that the assembly has not been tampered with and that the assembly being loaded is the one authored by the actual creator of the assembly. To do so, your assembly needs a digital signature when it is built.

Both of these requirements are met by strong names. Strong names must be globally unique and use public key encryption. A strong name is a string of hexadecimal digits and isn't meant to be human-readable.

To create a strong name, a public-private key pair is generated for one or more assemblies. A hash is taken of the names and contents of the files in the assembly. The hash is then encrypted with the private key for the assembly, and the public key token (an 8-byte hash of the full key) is placed in the manifest along with the public key. This is known as signing the assembly.

Public Key Encryption

Strong names are based on public key encryption technology. The essence of public key encryption is this: you create two keys. Data encrypted with the first key can only be decrypted with the second. Data encrypted with the second key can only be decrypted with the first.

Distribute your first key as a public key that anyone can have. Keep your second key as a private key that no one but you can have access to.

The reciprocal relationship between the keys allows anyone to encrypt data with your public key, and then you can decrypt it with your private key. No one else has access to the data once it is encrypted, including the person who encrypted it.

Similarly, you can encrypt data with your private key, and then anyone can decrypt that data with your public key. Although this makes the data freely available, it ensures that only you could have created it. This is called a digital signature.


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 clashes.

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 bytes and isn't 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.7.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. You can do so 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, open the File Explorer and navigate to %SystemRoot%\assembly; Explorer turns into a GAC utility.

17.7.5. Building a Shared Assembly

The best way to understand shared assemblies is to build one. Let's return to the earlier multimodule 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 don't have a local copy of the MySharedAssembly DLL files.

The referenced assembly (MySharedAssembly) should have its CopyLocal property set to false.


Run the program. It should fail with an exception saying it can't 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 put the assembly into the GAC (of course, you are also free to just use this strongly named assembly via xcopy deployment if you choose).

17.7.5.1 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:

[assembly: AssemblyKeyFile("")]

as follows:

[assembly: AssemblyKeyFile("keyFile.snk")]

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 manifest of MySharedAssembly.dll


By adding the strong name, you have signed this assembly (your exact values will be different). To illustrate that the names match in the GAC and in the reference in the client manifest, you'll want 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

Note that sn is case-sensitive. Don't write sn -t.


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 haven't yet registered it in the GAC.

17.7.5.2 Step 2: Put the shared assembly in the GAC

The next step is to drag the library into the GAC. To do so, open an Explorer window and navigate to the %SystemRoot% directory. When you double-click the Assembly subdirectory, Explorer turns into a GAC viewer.

You can drag and drop into the GAC viewer, or you can invoke this command-line utility:

Gacutil /i mySharedAssembly.dll

Just to close the circle, you might want to check that your assembly was loaded into the GAC, and that the public key token shown in the GAC viewer matches the value you got back from sn:

Public key token is 01fad8e0f0941a4d

This is illustrated in Figure 17-9.

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.

Close ILDasm, and run your code. It should work fine, even though there are no DLLs for this library in its immediate path. You've just created and used a shared assembly.

17.7.6. Other Required Assemblies

The assembly manifest also contains references to other assemblies. Each such reference includes the name of the other assembly, the version number and required culture, and optionally, the other assembly's public key token (a digital signature).

Culture is a string representing the language and national display characteristics for the person using your program. It is culture that determines, for example, whether dates are in month/date/year format or date/month/year format.



Programming C#(c) Building. NET Applications with C#
Programming C#: Building .NET Applications with C#
ISBN: 0596006993
EAN: 2147483647
Year: 2003
Pages: 180
Authors: Jesse Liberty

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net