Deploying Shared Assemblies

   


Implement versioning.

Plan, configure and deploy side-by-side deployments and applications.

A shared assembly is shared among multiple applications on a machine. It is reasonable to store a shared assembly in a common place that is well known to all the applications that use the assembly. However if shared assemblies are identified by just their name similar to the private assemblies, there is a problem. There might be a case in which two software publishers might use the same name for an assembly, thereby overwriting files and causing applications using those assemblies to behave abnormally.

To resolve this problem, the .NET Framework requires all shared assemblies to have a strong name. A strong name uses four attributes to identify an assembly:

  • Simple name

  • Version number

  • Culture identity (optional)

  • Public key token

A regular Windows folder can just differentiate files based on their simple name and not the strong name. Therefore, to store strongly named assemblies in a well-known shared location, you need a special type of storage. The .NET Framework provides this storage in the form of the Global Assembly Cache (GAC). In addition to providing a shared location, the GAC also provides the following benefits for shared assemblies:

  • Integrity Check When assemblies are installed in the GAC, the GAC applies a strong integrity check on the assembly. This check guarantees that the contents of the assembly have not been changed since it was built.

  • Security The GAC only allows users with administrator privileges to modify its contents.

  • Side-by-side Versioning Multiple assemblies with the same name but different version information can be maintained in the global assembly cache.

In this section, you'll learn the following about shared assemblies:

  • How to assign a strong name to an assembly

  • How to add an assembly to the GAC

  • How to reference an assembly from the GAC

  • The binding policy for shared assemblies

  • How the CLR binds to a shared assembly

  • How to delay sign a shared assembly

Assigning a Strong Name to an Assembly

To create a strong name, you need an assembly's simple name, version number, an optional culture identity, and a key pair. The key pair consists of two related pieces of binary data: a public key and a private key.

The public key represents the identity of a software publisher. When you create a strongly named assembly, the public key is stored in the assembly manifestalong with other identification information, such as name, version number, and culture. This scheme does not look foolproof because the public key is easily available from the assembly manifest and one can easily fake an assembly identity with some other company's public key. To verify that only the legitimate owner of the public key has created the assembly, an assembly is signed using the publisher's private key . The private key is assumed to be known only to the publisher of the assembly. The combination of a public key and a private key is known as a key pair . Key pairs have the property that data encrypted with the private key can only be decrypted using the public key. But it doesn't work the other way. That is, knowing the public key doesn't let you produce the encrypted data. It is also computationally infeasible to determine the private key if you know only the public key.

The purpose of this public-key cryptography is not to encrypt things so that they can't be decrypted. Rather, it is to encrypt them so that their origin is known. If you keep your private key private (as you should), you can use it to produce messages that can only come from you.

The process of signing an assembly and verifying its signature works like this:

  • Signing an assembly When you sign an assembly, a cryptographic hash of the assembly's contents is computed. The hash is then encoded with the private key and is stored within the assembly. The public key is stored in the assembly manifest.

  • Verifying the signature When the CLR verifies an assembly's identity, it reads the public key from the assembly manifest and uses it to decrypt the cryptographic hash that is stored in the assembly. It then recalculates the hash for the current contents of the assembly. If the two hashes match, this ensures two things: The contents of the assembly were not tampered with after the assembly was signed, and only the party that has a private key associated with the public key stored in the assembly has signed the assembly.

NOTE

Signing a Multifile Assembly If an assembly consists of multiple files, only the file that contains the assembly manifest needs to be signed. This is because the assembly manifest already contains file hashes for all the files that constitute the assembly implementation. The CLR can easily determine whether a file has been tampered with by matching its actual hash with what is stored in the assembly manifest.


You can easily generate public/private key pairs by using the Strong Name tool ( sn.exe ), which is available in the .NET Framework SDK.

Step by Step 10.5 shows you how to create a public/private key pair by using the Strong Name tool ( sn.exe ).

STEP BY STEP

10.5 Creating a Public/Private Key Pair by Using the Strong Name Tool ( sn.exe )

  1. From the Visual Studio .NET program group in the Windows Start menu, launch the Visual Studio .NET command prompt.

  2. Navigate to the 310C10 solution folder and issue the following command to create a pair of public/private keys:

     sn k 70310.snk 
  3. Both the public and private keys are created and stored in a file named 70310.snk .

NOTE

Create a Single Key File Because the key file is used to establish your identity, not the identity of your code, you should only create a single key file for an entire development organization.


Step by Step 10.6 shows you how to create a strongly named assembly. You'll use the key file generated in Step by Step 10.5 to assign a strong name to an assembly.

STEP BY STEP

10.6 Assigning a Strong Name to an Assembly

  1. Add a new Visual Basic .NET Class Library project to the solution. Name the project RandomNumberGenerator .

  2. Add a Component Class to the project and name it RandomNumberGenerator.vb . Delete Class1.vb .

  3. Switch to the code view of the component class. Add the following section of code just after the Component Designer generated code section:

     ' Stores minValue and maxValue Private m_minValue As Integer = 1 Private m_maxValue As Integer = 100 Public Property MinValue() As Integer     Get         MinValue = m_minValue     End Get     Set(ByVal Value As Integer)         m_minValue = Value     End Set End Property Public Property MaxValue() As Integer     Get         MaxValue = m_maxValue     End Get     Set(ByVal Value As Integer)         m_maxValue = Value     End Set End Property Public Function GetRandomNumber() As Integer     Dim r As Random = New Random()     GetRandomNumber = _      r.Next(m_minValue, m_maxValue) End Function 
  4. Open the AssemblyInfo.vb file of the RandomNumberGenerator project. Scroll down in the file and change the AssemblyVersion and AssemblyKeyFile attributes as follows :

     <Assembly: AssemblyVersion("1.0")> <assembly: AssemblyKeyFile("..\..\..310.snk")> 
  5. Build the project. RandomNumberGenerator.dll is generated, and a strong name is assigned to the file based on the specified key file.

In Step by Step 10.6, you change the AssemblyVersion attribute of the assembly from 1.0.* to 1.0 . The assembly's version consists of up to four parts :

 <major>.<minor>.<build>.<revision> 

If you want to use a fixed version value, you can hard-code it. The default value of the version uses an asterisk in place of build and revision numbers ; this changes the build and revision each time you compile the project. The build is calculated as the number of days since January 1, 2000, and the revision is calculated as the number of seconds since midnight divided by 2.

At runtime, the CLR uses version information to load a shared assembly. In the next few examples, you may change and compile your projects several times and as a result, you'll change the version of the assembly if you use the default version property. This will undesirably lead to having multiple versions of the same assembly installed in the GAC when you only wanted the most recent one.

To have the control of version numbers, in the examples of this chapter, I'll hard-code the version number. Shortly, you will also learn that if you willingly want to install multiple versions of an assembly in the GAC, you can still manage their side-by-side execution.

In Step by Step 10.6, you used Visual Studio .NET to attach a strong name to an assembly. If you want to do this from the command line, you can use the Assembly Linker tool ( al.exe ) with the keyfile option.

Adding an Assembly to the GAC

After you have associated a strong name with an assembly, you can place the assembly in the GAC. There are several ways you can add an assembly to the GAC. Using the Windows Installer is the recommended approach, but there are some quick alternatives, too. However, you should use these quick approaches only for development purposes; they are not recommended for installing assemblies on the end user 's computer.

Using the Windows Installer to Add an Assembly to the GAC

Using the Microsoft Windows Installer is the preferred way of adding assemblies to the GAC. The Windows Installer maintains a reference count for assemblies in the GAC and provides un-installation support. You will learn how to add assemblies using Windows Installer technology through the setup and deployment projects of Visual Studio .NET a little later in this chapter.

Using Windows Explorer to Add an Assembly to the GAC

The Assembly Cache Viewer Shell Extension ( shfusion.dll ) is installed as a part of the .NET Framework. This extension allows you to view the complex structure of the GAC using Windows Explorer and allows administrators to install and uninstall assemblies using drag-and-drop and menu operations.

STEP BY STEP

10.7 Adding an Assembly to the GAC by Using Windows Explorer

  1. Open Windows Explorer. Navigate to the assembly cache folder. It is usually c:\WINNT\assembly or C:\Windows\assembly (see Figure 10.6).

    Figure 10.6. The Assembly Cache Viewer Shell Extension enables you to view and manage the contents of the assembly cache by using Windows Explorer.

  2. Using Windows Explorer, drag the RandomNumberGenerator.dll file created in Step by Step 10.6 (in the bin folder of the project) and drop it in the assembly cache folder.

  3. In the assembly cache folder, right-click the RandomNumberGenerator.dll and select Properties from the shortcut menu. The Properties dialog box appears, as shown in Figure 10.7.

    Figure 10.7. You can view the properties of the RandomNumberGenerator assembly that is installed in the GAC.

If you want to remove a file from the GAC, you just delete it from Windows Explorer by selecting File, Delete or by selecting Delete from the assembly's shortcut menu.

NOTE

The Assembly Cache Folder The assembly cache folder actually contains two caches: the GAC and the native image cache. When you view the assembly cache folder by using Windows Explorer, the Assembly Cache Viewer Shell Extension shows you a combined list of both caches. You can determine whether an assembly is from the GAC or from the native image cache by looking at the Type field in the list. When you add an assembly to the assembly cache folder by using Windows Explorer, it is added to the GAC. You will learn about the native image cache and will learn how to add assemblies to it later in this chapter.


Using the .NET Framework Configuration Tool to Add an Assembly to the GAC

You can also use the .NET Framework Configuration tool ( mscorcfg .msc ) to manage an assembly in the GAC. Step by Step 10.8 guides you through the process of adding an assembly to the GAC by using .NET Framework Configuration tool.

STEP BY STEP

10.8 Adding an Assembly to the GAC by Using the .NET Framework Configuration Tool

  1. Open the Microsoft .NET Framework Configuration tool from the Administrative Tools section of Windows Control Panel. Select the Assembly Cache folder on the left pane under the My Computer node.

  2. In the right pane, click the hyperlink Add an Assembly to the Assembly Cache. The Add an Assembly dialog box appears. Navigate to the RandomNumberGenerator.dll file in the RandomNumberGenerator project and click the Open button.

  3. Click the other hyperlinkView List of Assemblies in the Assembly Cache. A list of installed assemblies appears. Ensure that the RandomNumberGenerator assembly is in this list, as shown in Figure 10.8.

    Figure 10.8. You can add assemblies to the GAC using the .NET Framework Configuration Tool.

To uninstall an assembly by using the .NET Framework Configuration tool, you just select Action, Delete or select Delete from the assembly's shortcut menu.

In addition to helping you add or remove assemblies, the .NET Framework Configuration tool helps you configure assemblies and manage their runtime security policies.

Using the Global Assembly Cache Tool ( gacutil.exe ) to Add an Assembly to the GAC

GacUtil.exe is a command-line tool that is especially useful for adding and removing assemblies from the GAC via a program script or a batch file. Step by Step 10.9 demonstrates the use of this tool.

STEP BY STEP

10.9 Adding an Assembly to the GAC by Using the Global Assembly Cache Tool

  1. From the Visual Studio .NET program group in the Windows Start menu, launch the Visual Studio .NET command prompt.

  2. Change the directory to the folder where the RandomNumberGenerator.dll file resides in the RandomNumberGenerator projectin this case, the project's bin directory.

  3. Issue the following command to install the assembly to the GAC, as shown here:

     gacutil /i RandomNumberGenerator.dll 

You can list all the assemblies in the GAC by using the gacutil.exe tool with the /l option. You can use the /u option with the name of the assembly (without the file extension) to uninstall the assembly from the GAC:

 gacutil /u RandomNumberGenerator 

You can also choose to uninstall from the GAC an assembly of a specific version and specific culture by specifying its version, culture, and public key, along with the name of the assembly:

[View full width]
 
[View full width]
gacutil /u RandomNumberGenerator,Version=1.0.0.0, Culture=neutral, PublicKeyToken=f26af4dbb33881b1

Referencing an Assembly from the GAC

Normally, when you refer an assembly in a Visual Studio .NET project, you can invoke the Add Reference dialog box and browse to the desired assembly. But after you have added an assembly to the GAC, this approach does not work because the GAC has a complex structure that cannot be directly enumerated by the Add Reference dialog box.

When you view the GAC by using the tools mentioned in the preceding section, you see an abstraction of its structure. If you instead switch to the command prompt and change the directory to the GAC folder, you see that the GAC is actually made up of various subdirectoriesone for each assembly. Each of these directories has subdirectories, whose names depend on the assemblies' versions and public keys. Each subdirectory stores the actual assembly file, along with some additional assembly information. Figure 10.9 shows how the GAC entry is made for the RandomNumberGenerator component on my computer.

Figure 10.9. You can see how the assemblies are maintained in the GAC by exploring the GAC through the command window.

A good practice is to keep a copy of the assemblies installed in the GAC somewhere outside the GAC, where they are easily accessible via a pathname. You can then easily reference these assemblies through the Add Reference dialog box by browsing to the correct path . .NET adds the reference, but instead of using the copy that you browsed to, it uses the copy in the GAC. In fact, the .NET Framework uses the same techniques for all of its own assemblies stored in the GAC. The .NET Framework also stores copies of those assemblies in the folder where the .NET Framework is installed.

Although you can add a reference to an assembly by browsing to the folder where it is stored, the convenient way is to have its name directly displayed in the Add Reference dialog box so that you can just check to select it.

Step by Step 10.10 shows how to instruct Visual Studio .NET to add assemblies that are stored in a custom folder to the Add Reference dialog box.

STEP BY STEP

10.10 Displaying an Assembly in the Add Reference Dialog Box

  1. Open the Registry Editor by launching regedit.exe from the Run dialog box, which you access by selecting Start, Run.

  2. In the Registry Editor, browse to the key named HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\AssemblyFolders .

  3. At this level create a new key and name it MyAssemblies .

  4. Double-click the (Default) value in the new key and change its value to the location of RandomNumberGenerator.dll in the bin folder of the RandomNumberGenerator project, as shown in Figure 10.10 (the actual path will be different on your system). Click OK.

    Figure 10.10. You can set values of a Registry key via the Edit String dialog box.

  5. Close the Registry Editor. Close all instances of Visual Studio .NET.

In Step by Step 10.11, you create a small Windows application that, when executed, loads the components installed in the GAC. Before you begin Step by Step 10.11, make sure that you have already installed the RandomNumberGenerator.dll file in the GAC.

STEP BY STEP

10.11 Creating a Windows Application That Uses the RandomNumberGenerator Component

  1. Launch Visual Studio .NET and load the 310C10 solution. Add a new Windows Application project to the solution and name it RandomNumberApp .

  2. In Solution Explorer, rename the Form1.vbs file RandomNumberApp.vb in the project. Switch to the code view of the form and modify all references to Form1 so that they refer to RandomNumberApp instead.

  3. Open the Add Reference dialog box and browse the list of files on the .NET tab. You should find the RandomNumberGenerator component in the .NET tab. Add a reference to the RandomNumberGenerator component. Set the Copy Local property of the RandomNumberGenerator reference to False .

  4. Activate the toolbox and then select the Components tab. Right-click an empty area on the tab and select Customize Toolbox from the shortcut menu. Click the .NET Framework Components tab and select RandomNumberGenerator.dll .

  5. Drag the RandomNumberGenerator component from the toolbox and drop it on the form. Change its MinValue property to 500 and change MaxValue to 1000 .

  6. Add a Label control ( lblResult ) and a Button control ( btnGenerate ) to the form. Empty the Label control's Text property. Set the Button control's Text property to Generate a Random Number! . Double-click the Button control to add an event handler for its Click event. Add the following code to the event handler:

     Private Sub btnGenerate_Click(_  ByVal sender As System.Object, _  ByVal e As System.EventArgs) _  Handles btnGenerate.Click     lblResult.Text = String.Format(_      "The next random number is: {0}", _      RandomNumberGenerator1.GetRandomNumber()) End Sub 
  7. Set the project RandomNumberApp as the Startup Project for the solution. Set the form as the Startup Object for the project.

  8. Run the solution. Click the button. A random number between 500 and 1,000 appears every time you press the button, as shown in Figure 10.11.

    Figure 10.11. A form that generates a random number by using the RandomNumberGenerator component installed in the GAC.

  9. Copy the RandomNumberApp.exe from the bin\ folder of the project to the C:\MyPrograms\RandomNumberApplication folder. Run the file from the new location and verify that the application works as expected.

In Step by Step 10.11, you added a reference to the assembly stored in the bin folder of the RandomNumberGenerator project. However, the application loads the assembly from the GAC instead of its copy in the bin folder. Even when you move the executable file, the referenced assembly continues to load from the GAC. To understand this, you need to understand how the CLR locates assemblies; this is discussed in the following section.

Binding Policy for Shared Assemblies

For shared assemblies, the binding policy specifies a set of rules that instructs

  • Which directories the CLR should search for an assembly

  • Which version of an assembly the CLR should attempt to locate

When the CLR searches for a shared assembly, it goes through three stages of binding policy resolution, as shown in Figure 10.12.

Figure 10.12. The CLR resolves the binding policy in three stages.

At each of these stages, you can specify binding rules in XML-based configuration files. The three stages, in order, are

  1. Application Policy Resolution At this stage, the CLR will look for an application configuration file for the binding rules. This configuration file can be used to specify additional search paths for an assembly. In addition, you can also use this file to redirect the CLR to a specific version of an assembly. The application-specific binding rules are usually set either by the application developer or by the administrator.

  2. Publisher Policy Resolution The next stage after the application policy resolution is the publisher policy resolution. Publisher policy is set by the publisher of a shared assembly to distribute service-packlike updates to the customers. For example, take a scenario in which a customer installs version 1.0.0.0 of an assembly from a vendor. Later, the vendor realizes that there are certain errors with this version and releases a service pack to fix those errors. In this case, the publisher distributes a new version 1.1 of the assembly along with a publisher policy that redirects all the already installed applications to use the new version 1.1 of the assembly instead of the old version 1.0.

    Publisher policy is specified using an XML file just like the application configuration file. But unlike the application configuration file, the publisher policy is complied into an assembly. In addition, the publisher policy only contains information about redirecting the CLR to a different version of the assembly.

    By default, the binding rules specified in the publisher policy overrides the application policy. If however, you want an application to override the updates and continue using the existing versions, you can bypass publisher policy file by specifying the <publisherPolicy apply="no"/> XML element in the application configuration file.

  3. Administrator Policy Resolution This is the final stage for applying the binding rules. The binding rules at this stage are specified by the administrator in the machine-wide configuration file named machine.config . This file is stored in the config subdirectory under the .NET Framework installation directory on a machine.

    The settings specified in the machine configuration file override any settings specified in the application policy and the publisher policy.

How the CLR Binds to a Shared Assembly

The CLR uses the following steps to locate a shared assembly:

  1. Determines the correct version of the assembly by examining the application configuration file, publisher policy file, and machine configuration file in the order mentioned in the previous section.

  2. Checks whether the assembly is already loaded. If the requested assembly has been loaded in one of the previous calls, the CLR binds to the already loaded assembly and stops searching any further.

  3. Checks the GAC. If the assembly is in the GAC, the CLR loads the assembly from there, binds to it, and stops searching any further.

  4. If a < codebase > element is specified in the configuration files, the CLR locates the assembly by using the paths specified in the <codebase> element. If the CLR finds the assembly, the binding is successful; otherwise , the binding request fails and the CLR stops searching any further.

  5. Follows the steps needed to probe for a private assembly as explained in the section "How the CLR Binds to a Privately Deployed Assembly" to locate the assembly.

Side-by-Side Execution of Shared Assemblies

Multiple versions of an assembly can exist in the GAC. Two common scenarios in which you might end up having multiple versions of an assembly are

  • A feature upgrade of an assembly is released.

  • A bug-fix service pack update of an assembly is released.

An application only binds to an assembly with the same identity with which the application was originally compiled. So if you release a new version of the assembly and remove the old one, existing applications will break because they will still be looking for an older version of the assembly.

Fortunately, the application, machine, and the publisher configuration files provide a mechanism to redirect the binding requests to a different version of the assembly without any need to recompile already deployed applications.

Side-by-Side Execution in a Feature Upgrade Scenario

Consider a scenario in which you have an application named RandomNumberApplication that uses version 1.0 of a shared component named RandomNumberGenerator . Now, a new version 1.1 of the RandomNumberGenerator component is released. You install that new version in the GAC. Some of the applications on your server still use version 1.0 of the component. You want the already deployed RandomNumberApplication to start using version 1.1 of the component. You do not want to recompile the RandomNumberApplication and also do not want to affect the installation of other applications on the server.

The best policy in the preceding scenario is to modify the application configuration file of RandomNumberApplication to redirect any request from version 1.0 of RandomNumberGenerator to version 1.1 of that assembly. Modifying configuration files does not require the application to be recompiled, and if you modify the application configuration file, it only affects the application to which it belongs.

To demonstrate the scenario, Step By Step 10.12 installs version 1.1 of RandomNumberGenerator assembly in the GAC.

STEP BY STEP

10.12 Installing Multiple Versions of an Assembly in the GAC

  1. Open the RandomNumberGenerator.vb file in the RandomNumberGenerator project.

  2. Modify the GetRandomNumber() method as follows:

     Public Function GetRandomNumber() As Integer     Dim r As Random = New Random()     Dim rand As Integer = _      r.Next(m_minValue, m_maxValue)     Dim e As EventLog = New EventLog()     e.Source = "RandomNumberGenerator 1.1"     e.WriteEntry(_      "Random Number Generated:" & rand)     GetRandomNumber = rand End Function 
  3. Open the AssemblyInfo.vb file. Scroll down in the file and change the AssemblyVersion as shown here:

     <Assembly: AssemblyVersion("1.1")> 
  4. Build the RandomNumberGenerator project. You should see the RandomNumberGenerator.dll file generated with version 1.1.

  5. Copy the strongly named assembly RandomNumberGenerator.dll to the GAC. You should be able to see that the GAC now has two versions of the RandomNumberGenerator assembly, as shown in Figure 10.13.

    Figure 10.13. You can perform side-by-side versioning of shared assemblies in the GAC.

  6. Run the RandomNumberApp.exe file from the C:\MyPrograms\RandomNumberApplication folder. You should notice that the file still uses version 1.0 of the RandomNumberGenerator component (with which it was compiled) and does not create an entry in the event log.

From Step By Step 10.12, you can see that the RandomNumberApp is still using the older version of the component because that's what is stored in its assembly manifest.

Step By Step 10.13 shows how you can modify the application configuration file for RandomNumberApp.exe to use version 1.1 of the RandomNumberGenerator .

STEP BY STEP

10.13 Configuring Application-level Binding Policy for an Assembly Using the .NET Framework Configuration Tool

  1. Open the Microsoft .NET Framework Configuration tool from the Administrative Tools section of the Windows Control Panel.

  2. Click the Applications node in the tree view.

  3. Click the Add an Application to Configure link.

  4. In the Configure an Application dialog box, click the Other button and browse to the C:\MyPrograms\RandomNumberApplication folder to select RandomNumberApp.exe . Select this application and click Open.

  5. Expand the new node in the tree view and click the Configured Assemblies child node.

  6. Click the Configure an Assembly link.

  7. In the Configure an Assembly dialog box, select the option button to choose an assembly from the list of assemblies that this application uses. Click the Choose Assembly button. Select the RandomNumberGenerator assembly, click Select, and then click Finish.

  8. In the RandomNumberGenerator Properties dialog box, select the Binding Policy tab. Enter 1.0.0.0 as the requested version and 1.1.0.0 as the new version, as shown in Figure 10.14.

    Figure 10.14. You can create a configured assembly and set its binding policy and other settings with the help of the Microsoft .NET Framework Configuration tool.

  9. Click OK to save the configured assembly information.

  10. View the C:\MyPrograms\RandomNumberApplication folder in Windows Explorer. You should find a RandomNumberApp.exe.config application configuration file added to the folder with the following contents:

     <?xml version="1.0"?> <configuration>   <runtime>     <assemblyBinding      xmlns="urn:schemas-microsoft-com:asm.v1">       <dependentAssembly>         <assemblyIdentity name="RandomNumberGenerator"          publicKeyToken="0556152c9715d60f" />         <bindingRedirect oldVersion="1.0.0.0"          newVersion="1.1.0.0" />       </dependentAssembly>     </assemblyBinding>   </runtime> </configuration> 
  11. Double-click the RandomNumberApp.exe file from the C:\MyPrograms\RandomNumberApplication folder in Windows Explorer. Click the button and notice that version 1.1.0.0 of the RandomNumberGenerator component is executed by checking the entries in the Application event log.

WARNING

No Validation The .NET Framework Configuration tool performs no validation to determine whether the specified new version of the assembly even exists, let alone whether it has the proper interface for the application.


In Step by Step 10.13, you used the .NET Framework configuration tool to create an application configuration file. You can also create the application configuration file manually, although in that case you need to know that you have to use the <assemblyBinding> element and its sub-elements to redirect the version numbers.

Note that, in the <bindingRedirect> element, the values for the attribute oldVersion and newVersion need not be an old version and a new version, respectively. You can, in fact, redirect an application using a newer version of an assembly to an older version also (provided, of course, that the changes are non-breaking).

When you use the application configuration file, you can only configure a single application. What if an administrator needs to configure all the applications on a machine that uses the old version of RandomNumberGenerator to use its new version? In this case, it would be tedious to configure an assembly for each application. Further, you would also need to take care that the new applications installed also bind to the new version of the component. To ease this, you can add the <assemblyBinding> element to the machine.config file. However, you need administrator privileges to edit the machine.config file. Step by Step 10.14 shows you how to configure an assembly for a machine using the .NET Framework Configuration tool.

STEP BY STEP

10.14 Configuring Machine-level Binding Policy for an Assembly Using the .NET Framework Configuration Tool

  1. Open the Microsoft .NET Framework Configuration tool from the Administrative Tools section of the Windows Control Panel.

  2. Right-click the Configured Assemblies node in the tree view and select Add from its context menu.

  3. In the Configure an Assembly dialog box, select the option button to choose an assembly from the assembly cache. Click the Choose Assembly button. Select the RandomNumberGenerator assembly version 1.0.0.0, click Select, and then click Finish.

  4. In the RandomNumberGenerator Properties dialog box, select the Binding Policy tab. Enter 1.0.0.0 as the requested version and 1.1.0.0 as the new version.

  5. Click OK to save the configured assembly information.

  6. Open the machine.config file from the config folder of the Microsoft .NET Framework installation folder. Navigate to the <assemblyBinding> element and verify that the binding policy for the RandomNumberGenerator component is added as shown here:

     <configuration> ...   <runtime>     <assemblyBinding         xmlns="urn:schemas-microsoft-com:asm.v1">       ...       <dependentAssembly>         <assemblyIdentity name="RandomNumberGenerator"           publicKeyToken="0556152c9715d60f" />         <bindingRedirect oldVersion="1.0.0.0"             newVersion="1.1.0.0" />       </dependentAssembly>     </assemblyBinding>   </runtime> </configuration> 
  7. Delete the RandomNumberApp.exe.config application configuration file from the C:\MyPrograms\RandomNumberApplication folder in Windows Explorer.

  8. Double-click the RandomNumberApp.exe file from the C:\MyPrograms\RandomNumberApplication folder in Windows Explorer. Click the button and notice that version 1.1.0.0 of the RandomNumberGenerator component is executed by checking the entries in the Application event log.

The configuration performed in Step by Step 10.14 affects not only the RandomNumberApp application, but also, in fact, any application that uses the RandomNumberGenerator component on the given machine.

Side-by-Side Execution in a Service Pack Update Scenario

Consider another scenario in which you might end up having multiple versions of an assembly in the GAC. In this scenario, you are the company that publishes the RandomNumberGenerator component. You release version 1.0 of the component. Your customers develop applications such as RandomNumberApp that use the component. Then customers report that a bug is in the component that needs to be fixed at high priority. You plan to release a service pack of the component. The new version of the component is version 1.1. You want to deploy the component on the customer's computers in such a way that all existing applications that refer to version 1.0 of the RandomNumberGenerator component should now be redirected to version 1.1. You do not want extra configuration steps on the part of administrators on the customer's side.

The .NET Framework provides publisher policy for such a scenario. A publisher policy can be configured using the publisher policy configuration file, which uses a format similar to that of the application configuration files. But unlike the application configuration file, a publisher policy file needs to be compiled into an assembly and placed in the GAC.

The steps involved in creating a publisher policy are as follows:

  1. Create a publisher policy file.

  2. Use the assembly generation tool ( al.exe ) to convert the publisher policy file into a strongly named assembly. The name of the assembly should be of the format policy. majorNumber.minorNumber.AssemblyName.dll . Here, majorNumber and minorNumber are the version numbers of the existing assembly for which you want to redirect the binding requests. AssemblyName is the name of the assembly.

  3. Install the publisher policy assembly to the GAC.

Step by Step 10.15 shows you how to create a publisher policy by using the .NET Framework Configuration tool.

STEP BY STEP

10.15 Configuring a Publisher Policy for an Assembly

  1. Create a new publisher configuration file named policy.1.0.RandomNumberGenerator.Config in the folder where the original RandomNumberGenerator.dll resides using the following code. You'll need to change the publicKeyToken attribute to the appropriate public key for your assembly (which you can locate in the configuration file that you built in Step by Step 10.14):

     <configuration>    <runtime>       <assemblyBinding         xmlns="urn:schemas-microsoft-com:asm.v1">        <dependentAssembly>          <assemblyIdentity             name="RandomNumberGenerator"             publicKeyToken="0556152c9715d60f" />          <bindingRedirect oldVersion="1.0.0.0"             newVersion="1.1.0.0"/>        </dependentAssembly>       </assemblyBinding>    </runtime> </configuration> 
  2. Launch the Visual Studio .NET prompt. Navigate to the folder where the publisher configuration file resides and run the following command:

    [View full width]
     
    [View full width]
    al /link:policy.1.0.RandomNumberGenerator.config/out:policy.1.0. RandomNumberGenerator.dll/keyfile:..\..310.snk

    You should see a publisher policy assembly named policy.1.0.RandomNumberGenerator.dll being generated.

  3. Add this new publisher policy assembly to the GAC.

  4. Open the Microsoft .NET Framework Configuration tool from the Administrative Tools section of the Windows Control Panel.

  5. Select the Configured Assemblies. Click the View List of Configured Assemblies link. In the right pane, delete the RandomNumberGenerator assembly added in Step by Step 10.14. Now the assembly binding entries from the machine.config file are removed.

  6. Double-click the RandomNumberApp.exe file from the C:\MyPrograms\RandomNumberApplication folder in Windows Explorer. Click the button and confirm that version 1.1.0.0 of the RandomNumberGenerator component is executed by checking the entries in the Application event log. The version 1.1.0.0 assembly is run because of the assembly bindings in the publisher policy assembly.

Binding redirections specified in machine.config override those specified in the publisher policy. The publisher policy overrides the setting specified in the application configuration file. But an application can choose to ignore the publisher policy altogether by specifying the following XML element in the application configuration file:

 <publisherPolicy apply="no"/> 

Delay Signing an Assembly

In Step by Step 10.6, when you signed an assembly, you used a key file that contains both the public and private keys for a company. As discussed earlier in the chapter, the private key ensures that the assembly is signed only by its advertised publisher. Thus, in most companies, the private key is stored securely, and only a few people have access to it.

If the key is highly protected, it might be difficult to frequently access the key when multiple developers of a company are building assemblies several times a day. To solve this problem, the .NET Framework uses the delay signing technique for assemblies.

When you use delay signing, you use only the public key to build an assembly. Associating public keys with an assembly allows you to place the assembly in the GAC and complete most of the development and testing tasks with the assembly. Later, when you are ready to package the assembly, an authorized person signs the assembly with the private key. Signing with the private key ensures that the CLR will provide tamper protection for the assembly. The following list summarizes the various steps involved with delay signing:

  1. Extract a public key from the public/private key pair To extract the public key from a file that is storing the public/private key pair, you use the Strong Name tool as follows:

     sn.exe p 70310.snk 70310PublicKey.snk 

    At this stage, the 70310PublicKey.snk file can be freely distributed to the development team, and the 70310.snk file that contains both the private and public keys can be stored securely, possibly on a hardware device such as smart card.

  2. Delay signing an assembly using Visual Studio .NET To use delay signing in a Visual Studio .NET project, you need to modify the following two attributes of the project's AssemblyInfo.vb file and build the assembly:

     <Assembly: AssemblyDelaySign(true)> <Assembly: AssemblyKeyFile("70310PublicKey.snk")> 
  3. Turn off verification for an assembly in the GAC By default, the GAC verifies the strong name of each assembly. If the assembly is not signed by using the private key, this verification fails. So for development and testing purposes, you can relax this verification for an assembly by issuing the following command:

     sn.exe Vr RandomNumberGenerator.dll 

    If you execute this command, the GAC always skips the verification for this assembly in the future.

  4. Sign a delay-signed assembly with the private key When you are ready to deploy a delay-signed assembly, you need to sign it with the company's private key:

     sn.exe R RandomNumberGenerator.dll 70310.snk 
  5. Turn on verification for an assembly in the GAC Finally, you can instruct the GAC to turn on verification for an assembly by issuing the following command:

     sn.exe Vu RandomNumberGenerator.dll 
Delay Signing Using the Assembly Linker Tool

The Assembly Linker tool ( al.exe ) generates an assembly with an assembly manifest from the given modules or resource files. Remember that a module is a Microsoft Intermediate Language (MSIL) file without an assembly manifest.

While generating an assembly, you can also instruct the Assembly Linker tool to sign or delay sign an assembly with the given public/private key file. When you use al.exe for delay signing, you also use the arguments listed in Table 10.1.

Table 10.1. Arguments Passed to al.exe for Delay Signing

Argument

Description

< sourcefiles >

You replace < sourcefiles > with the names of one or more complied modules that will be the parts of the resulting assembly.

/delay[sign][+-]

You can use either the delay argument or the delay[sign] argument for delay signing. The option + is used to delay sign the assembly by storing just the public key manifest in the assembly manifest.

The option is used to fully sign an assembly by using both public and private keys.

If you do not use either + or , the default value of is assumed.

/keyf[ile]:< filename >

You can use either keyf or keyfile to specify the key file. You replace < filename > with the name of the file that stores the key(s).

/out:< filename >

You replace < filename > with the desired name of the output assembly file.

Assume that you want to create an assembly by linking two modules, Sample1.netmodule and Sample2.netmodule . The public key file is SamplePublicKey.snk , and the desired output assembly is SignedSample.exe . You would use the al.exe command as follows:

[View full width]
 
[View full width]
al.exe Sample1.netmodule,Sample2.netmodule/delaysign+ /keyfile:SamplePublicKey.snk/out: SignedSample.exe

REVIEW BREAK

  • Shared assemblies are used by multiple applications on a machine. Shared assemblies are placed in the GAC and they enjoy special privileges such as file security, shared location, and side-by-side versioning.

  • You generate a public/private key pair by using the Strong Name tool ( sn.exe ). This pair can be used to sign assemblies with a strong name.

  • You can add a shared assembly to the GAC by using Windows Explorer, the .NET Framework Configuration tool, the Global Assembly Cache tool, and the Windows Installer.

  • The best way to add an assembly in the GAC during deployment is to use Microsoft Windows Installer. The Windows Installer provides assembly reference-counting features and manages removal of assemblies at the time of uninstallation.

  • When viewed in Windows Explorer, the assembly cache folder located under the Windows folder displays assemblies from the GAC and native image cache.

  • The CLR first searches the GAC to locate assemblies, and then it looks into the files and folders where the assembly is installed. Thus, loading shared assemblies from the GAC is efficient because the CLR does not engage itself in looking into the <codebase> and <probing> elements of the applicable configuration files.

  • Different versions of an assembly can be deployed in the GAC for side-by-side execution. You can implement side-by-side execution of an assembly by configuring the binding policy in the application configuration, publisher policy file, or the machine configuration file.

  • The publisher policy file can be used to deploy service packlike bug-fix updates for the assemblies. The publisher policy file is an XML file that is converted into a strongly named assembly and installed in the GAC.

  • Delay signing allows you to place a shared assembly in the GAC by signing the assembly with just the public key. This allows the assembly to be signed with the private key at a later stage, when the development process is complete and the component or assembly is ready to be deployed. This process allows developers to work with shared assemblies as if they were strongly named, and it secures the private key of the signature from being accessed at different stages of development.


   
Top


MCAD. MCSD Training Guide (Exam 70-310. Developing XML Web Services and Server Components with Visual Basic. NET and the. NET Framework)
MCAD/MCSD Training Guide (70-310): Developing XML Web Services and Server Components with Visual Basic(R) .NET and the .NET Framework
ISBN: 0789728206
EAN: 2147483647
Year: 2002
Pages: 166

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