C Sharp

Creating Shared Assemblies

Sharing assemblies is done when an assembly is to be used with multiple applications and versioning is important. (We'll get to versioning in the next section.) To share an assembly, you must create a shared name (also known as a strong name) for the assembly by using the Strong Name tool that accompanies the .NET SDK. The four main four benefits derived from using strong names are the following: -

  • It's the mechanism in .NET for generating a globally unique name.
  • Because the generated key pair (explained shortly) includes a signature, you can tell whether it's been tampered with after its original creation.
  • Strong names guarantee that a third party can't release a subsequent version of an assembly you built. Once again, this is because of signatures-the third party won't have your private key.
  • When .NET loads an assembly, the runtime can verify that the assembly came from the publisher that the caller is expecting.

The first step to creating a strong name is to use the Strong Name tool to create a key file for the assembly. This is done by specifying the -k switch with the name of the output file that will contain the key. Here we'll just make something up-InsideCSharp.key-and create the file as follows: -

sn -k InsideCSharp.key

Upon running this, you should get a confirmation message like the following: -

Key pair written to InsideCSharp.key

Now add the assembly:AssemblyKeyFile attribute to the source file. Here, I've created another simple set of files to illustrate how this is done: -

// Module3Server.cs
// build with the following command line switches
//     csc /t:module Module3Server.cs
internal class Module3Server
{
}
// Module3ClientApp.cs
// build with the following command line switches
//     csc /addmodule:Module3Server.netmodule Module3ClientApp.cs
using System;
using System.Diagnostics;
using System.Reflection;
[assembly:AssemblyKeyFile("InsideCSharp.key")]
class Module3ClientApp
{
    public static void Main()
    {
        Assembly DLLAssembly =
            Assembly.GetAssembly(typeof(Module3Server));
        Console.WriteLine("Module1Server.dll Assembly Information");
        Console.WriteLine("\t" + DLLAssembly);
        Process p = Process.GetCurrentProcess();
        string AssemblyName = p.ProcessName + ".exe";
        Assembly ThisAssembly = Assembly.LoadFrom(AssemblyName);
        Console.WriteLine("Module1Client.dll Assembly Information");
        Console.WriteLine("\t" + ThisAssembly);
    }
}

As you can see, the assembly:AssemblyKeyFile attribute's constructor takes the name of the key file that was generated with the Strong Name utility and is the means by which you specify a key pair to be used to give your assembly a strong name. One more important point to understand is that this attribute is an assembly-level attribute. Therefore, technically, it can be placed in any file in the assembly and isn't attached to a specific class. However, it's customary to place this attribute just below the using statements and before any class definitions.

Now when you run the application, take note of the PublicKeyToken value of the assembly. This value was null in the previous two examples because those assemblies were considered to be private assemblies. However, now the assembly has been defined as a shared assembly, and so the assembly has an associated public key token.

Module3Server.dll Assembly Information
    Module3Client, Version=0.0.0.0, Culture=neutral,
    PublicKeyToken=6ed7cef0c0065911
Module3Client.dll Assembly Information
    Module3Client, Version=0.0.0.0, Culture=neutral,
    PublicKeyToken=6ed7cef0c0065911

-According to the Assembly object that we instantiated for this demo assembly, it is shared. However, how do we know which assemblies in our .NET system are shared? The answer is the global assembly cache. In the next section, I'll cover this part of .NET and explain the role it plays in shared assemblies. -