So you're ready to deploy version 1.1 of your library, and you'd like it to replace version 1.0 for existing applications. Or perhaps something else has globally upgraded to 1.1, and you need to downgrade it for a particular application where 1.1 is causing problems. Handling these issues for .NET applications is the job of runtime binding policy. In this article, I'll explain the basics of runtime binding policy, and show you how you can customize the process for your own applications.
.NET applications use two different types of assemblies: private assemblies and shared assemblies. Private assemblies are identified by their name and are deployed for the use of only a single application. Shared assemblies are identified by a strong name (a type of digital identity that includes the name of the assembly, its version number, its culture identity, and a public key token).
When you build an assembly, information about all other assemblies that it refers to is stored in the assembly manifest. The manifest, however, does not store the exact path of the assembly because this path may might differ on the computer where the assembly is deployed. At runtime, when a class is referenced, the Common Language Runtime (CLR) reads the assembly manifest, retrieves the identification information for the referenced assembly, and then attempts to locate the referenced assembly. The mechanism used by the CLR to locate a private assembly is different from that used for a shared assembly. It's easy for the CLR to tell the difference, because public key tokens are only stored in the manifest for shared assemblies.
Here are the steps that the CLR takes when you call code from a private assembly:
<probing>element, as in this example:
This particular example adds the bin\path1 and bin\path2 folders to the list that the CLR checks for private assemblies.
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="bin\path1;bin\path2" /> </assemblyBinding> </runtime> </configuration>
<probing>element of the application configuration file. Of course, if there are more than two hints, each one is searched in turn. As soon as the CLR finds a matching assembly, it binds to the assembly and stops searching.
Here are the steps that the CLR takes when you call code from a shared assembly:
<codebase>element in the application's configuration file. If one is present, it checks that path for the assembly, loading it if found.
Here's where it gets fun. Remember that I started the article by discussing scenarios in which you might like to customize the binding process? You can do this with a series of configuration files that allow you to tell an application to use a particular version of a shared assembly, even if it was compiled with a different version. These binding policies are applied at three levels:
In the application policy resolution stage, the CLR checks for a
<bindingRedirect> tag in the application's configuration
file, similar to this example:
<?xml version="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="MyCalledAssembly" publicKeyToken="0556152c9715d60f" /> <bindingRedirect oldVersion="184.108.40.206" newVersion="220.127.116.11" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
This file tells the CLR to load version 18.104.22.168 of
though the application was compiled to use version 22.214.171.124.
In the publisher policy resolution stage, the CLR checks for a policy file distributed with the assembly itself. A publisher policy file starts as an XML file, very similar to an application configuration file:
<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="MyCalledAssembly" publicKeyToken="0556152c9715d60f" /> <bindingRedirect oldVersion="126.96.36.199" newVersion="188.8.131.52"/> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
This particular publisher policy file tells the CLR to use version 184.108.40.206 of
the assembly to satisfy requests for version 220.127.116.11. Before a publisher policy
file can take effect, it must be compiled, using the
al /link:policy.1.0.MyCalledAssembly.config /out:policy.1.0.MyCalledAssembly.dll /keyfile:..\..\MyKeyFile.snk
The compiled publisher policy file can then be installed in the GAC along
with the assembly to which it refers. Publisher policy files generally override
application policy. However, you can force your application to ignore a
publisher policy file by adding
to your application configuration file.
The final stage in applying policy rules is administrator policy resolution. The administrator of a computer can specify system-wide binding rules in the machine.config file. These rules override both application policy and publisher policy. These machine.config settings use the same format as the binding policy settings in the application configuration file.
You can configure both application binding policy and administrator binding policy without editing XML files by hand. These are among the tasks that the .NET Framework Configuration tool (which you can launch from Start-Programs- Administrative Tools) can perform. If you launch this tool and expand the tree, as shown in FIgure 1, you'll find two places where you can work with configured assemblies.
|Figure 1: Working with configured assemblies in the Microsoft .NET Framework Configuration Tool|
A configured assembly is simply one that has an explicit binding policy. The Configured Assemblies node directly beneath My Computer lets you set administrator policy for configured assemblies. The other nodes, beneath specific applications, let you set application policy for configured assemblies. To work with a specific application in this tool, click on the Applications node, select "Add an Application to Configure," and follow the instructions to add your application to the tree.
Whether you're working at the application or the administrator level, the procedures here are the same. Click on one of the Configured Assemblies nodes, and you'll have two choices. The first choice allows you to add a new configured assembly to the list for the application or computer. The second allows you to view a list of all configured assemblies. From the list, you can double-click an assembly to set its properties. Figure 2 shows the properties dialog box.
|Figure 2: Setting policy properties for a configured assembly|
The properties dialog box has three tabs:
As with some other areas of the .NET Framework, binding resolution offers an overwhelming number of options. I'll leave you with some thoughts on ways in which you might choose to use these options.
Mike Gunderloy is the lead developer for Larkware and author of numerous books and articles on programming topics.
Return to ONDotnet.com
Copyright © 2009 O'Reilly Media, Inc.