Configuration

 
Chapter 8 - Assemblies
bySimon Robinsonet al.
Wrox Press 2002
  

COM components used the registry to configure components . Configuration of .NET applications is done using configuration files. With registry configurations, an xcopy-deployment is not possible. The configuration files use XML syntax to specify startup and runtime settings for applications.

In this section, we shall explore:

  • What can be configured using the XML base configuration files

  • How a strong named referenced assembly can be redirected to a different version

  • How to specify the directory of assemblies to find private assemblies in subdirectories and shared assemblies in common directories or on a server

Configuration Categories

We can group the configuration into these categories:

  • With startup settings, the version of the required runtime can be specified. It's possible that different versions of the runtime could be installed on the same system. With the < startup > element, the version of the runtime can be specified.

  • With the runtime settings we can specify how garbage collection is performed by the runtime, and how the binding to assemblies works. We can also specify the version policy and the code base with these settings. We will take a more detailed look into the runtime settings later in this chapter.

  • Remoting settings are used to configure applications using .NET Remoting. We will look into these configurations in Chapter 21.

  • Security settings will be introduced in Chapter 23, and configuration for cryptography and permissions is done there.

These settings can be given in three types of configuration files:

  • Application configuration files include specific settings for an application, such as binding information to assemblies, configuration for remote objects, and so on. Such a configuration file is placed into the same directory as the executable; it has the same name as the executable with a .config appended. ASP.NET configuration files are named web.config .

  • Machine configuration files are used for system-wide configurations. We can also specify assembly binding and remoting configurations here. During a binding process, the machine configuration file is consulted before the application configuration file. The application configuration can override settings from the machine configuration. The application configuration file should be the preferred place for application-specific settings so that the machine configuration file stays smaller and manageable. A machine configuration file is located in %runtime_install_path%\config\Machine.config .

  • Publisher policy files can be used by a component creator to specify that a shared assembly is compatible with older versions. If a new assembly version just fixes a bug of a shared component it is not necessary to put application configuration files in every application directory that uses this component; instead, the publisher can mark it as "compatible" by adding a publisher policy file. In the case that the component doesn't work with all applications it is possible to override the publisher policy setting in an application configuration file. In contrast to the other configuration files, publisher policy files are stored in the global assembly cache.

How are these configuration files used? How a client finds an assembly (also called binding ) depends upon whether the assembly is private or shared. Private assemblies must be in the directory of the application or a subdirectory thereof. A process called probing is used to find such an assembly. For probing, the version number is not used, but the culture is an important aspect as we've seen in our localization example.

Shared assemblies can be installed in the global assembly cache, placed in a directory, a network share, or on a web site. We specify such a directory with the configuration of the codeBase, as we will see soon. The public key, version, and culture are all important aspects when binding to a shared assembly. The reference of the required assembly is recorded in the manifest of the client assembly, including the name, the version, and the public key token. All configuration files are checked to apply the correct version policy. The global assembly cache and code bases specified in the configuration files are checked, followed by the application directories, and probing rules are then applied.

Versioning

For private assemblies, versioning is not important because the referenced assemblies are copied with the client. The client uses the assembly it has in its private directories.

This is, however, different for shared assemblies. Let's look at the traditional problems that can occur with sharing. Using shared components, more than one client application can use the same component. The new version can break existing clients when updating a shared component with a newer version. We can't stop shipping new versions because new features are requested and introduced with new versions of existing components. We can try to program carefully to be backwards -compatible, but that's not always going to be possible.

A solution to this dilemma could be an architecture that allows installation of different versions of shared components, with clients using the version that they referenced during the build process. This solves a lot of problems, but not all of them. What happens if we detect a bug in a component that's referenced from the client? We would like to update this component and make sure that the client uses the new version instead of the version that was referenced during the build process.

Therefore, depending on the type in the fix of the new version, sometimes we want to use a newer version, and sometimes we want to use the older referenced version. All this is possible with the .NET architecture.

In .NET, the original referenced assembly is used by default. We can redirect the reference to a different version using configuration files. Versioning plays a key role in the binding architecture how the client gets the right assembly where the components live.

Version Numbers

Assemblies have a four-part version number, for example. 1.0.479.36320 . The parts are:

 <Major>.<Minor>.<Build>.<Revision> 

How these numbers are used depends on your application configuration.

Important 

A good policy would be that you change the major or minor number on changes incompatible with the previous version, but just the build or revision number with compatible changes. This way we can assume that redirecting an assembly to a new version where just the build and revision changed is safe.

We specify the version number in the assembly with the assembly attribute AssemblyVersion . In Visual Studio .NET projects we find this attribute in AssemblyInfo.cs :

   [assembly: AssemblyVersion("1.0.*")]   

The first two numbers specify the major and minor version, and the " * " means that the build and revision numbers are auto-generated. The build number is the number of days since January 1st, 2000, and the revision is the number of seconds since midnight local time. Of course, you can also specify four values, but be sure to change the numbers when rebuilding the assembly.

This version is stored in the .assembly section of the manifest.

Referencing the assembly in the client application stores the version of the referenced assembly in the manifest of the client application.

Getting the Version Programmatically

To make it possible to check the version of the assembly that is used from our client application, we are adding the method GetAssemblyFullName() to the SimpleShared class to return the strong name of the assembly. For easy use of the Assembly class, we have to add the System.Reflection namespace:

   public string GetAssemblyFullName()     {     Assembly assembly = Assembly.GetExecutingAssembly();     return assembly.FullName;     }   

The FullName property of the Assembly class holds the name of the class, the version, the locality, and the public key token as you see in our output below, when calling GetAssemblyFullName() in our client application.

In the client application, we just add a call to GetAssemblyFullName() in the Main() method after creating the shared component:

 static void Main(string[] args) {    SimpleShared quotes = new SimpleShared(@"C:\ProCSharp\Assemblies\Quotes.txt");   Console.WriteLine(quotes.GetAssemblyFullName());   

Be sure to register the new version of the shared assembly SimpleShared again in the global assembly cache using gacutil . If the referenced version cannot be found, you will get a System.IO.FileLoadException , because the binding to the correct assembly failed.

With a successful run, we can see the full name of the referenced assembly:

click to expand

Using this client program, we can now try different configurations of this shared component.

Application Configuration Files

With a configuration file we can specify that the binding should happen to a different version of a shared assembly. Let's say we create a new version of the shared assembly SimpleShared with major and minor versions 1.1. We don't want to rebuild the client we just want to use the new version of the assembly with the existing client. This is useful in cases where either a bug is fixed with the shared assembly, or we just want to get rid of the old version because the new version is compatible.

With the global assembly cache viewer, we can see that the versions 1.0.735.36320 , 1.0.741.29127 , and 1.1.741.31355 are installed for the SimpleShared assembly:

click to expand

The manifest of the client application says that the client references version 1.0.741.29127 of the assembly SimpleShared :

click to expand

Now we need an application configuration file. It's not necessary to work directly with XML; the .NET Framework Configuration tool can create application and machine configuration files. The .NET Framework Configuration tool is a MMC Snap-in that can be started from the Administrative Tools in the Control Panel:

click to expand

Selecting Applications on the left side, and the menu Action Add... a list shows all .NET applications that have been previously started on this computer. We can select the Client.exe application to create an application configuration file for this application. After adding our client application to the .NET Admin Tool, we can view the assembly dependencies:

click to expand

Selecting Configured Assemblies and the menu Action Add... we can configure the dependency of the assembly SimpleShared from the dependency list:

click to expand

For the Requested Version , we specify the version that's referenced in the manifest of the client assembly. New Version specifies the new version of the shared assembly. In the above picture we specify that the version 1.1.741.31355 should be used instead of any version in the range of 1.0.0.0 to 1.0.999.99999.

Now we can find an application configuration file Client.exe.config in the directory of the Client.exe application that includes this XML code:

   <?xml version="1.0"?>     <configuration>     <runtime>     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">     <dependentAssembly>     <assemblyIdentity name="SimpleShared"     publicKeyToken="be9f9ce7b9a0a62f" />     <bindingRedirect oldVersion="1.0.0.0-1.0.999.99999"     newVersion="1.1.741.31355" />     </dependentAssembly>     </assemblyBinding>     </runtime>     </configuration>   

With the < runtime > element, runtime settings can be configured. The sub-element of < runtime > is < assemblyBinding >, which in turn has a sub-element < dependentAssembly >. < dependentAssembly > has a required sub-element < assemblyIdentity >. We specify the name of the referenced assembly with < assemblyIdentity >. name is the only mandatory attribute for < assemblyIdentity >. The optional attributes are publicKeyToken and culture . The other sub-element of < dependentAssembly > that's needed for version redirection is < bindingRedirect >. With this element the old and the new version of the dependent assembly is specified.

Starting the client with this configuration file, we get the redirected version 1.1.741.31355.

Publisher Policy Files

Using assemblies that are shared in the global assembly cache it is also possible to use publisher policies to override versioning issues. Let's assume that we have a shared assembly that is used by some applications. What if a bug is found in the shared assembly? We have seen that it is not necessary to rebuild all the applications that use this shared assembly as we can use configuration files to redirect to the new version of this shared assembly. Maybe we don't know all the applications that use this shared assembly, but we want to get the bug fix to all of them. In that case we can create publisher policy files to redirect all applications to the new version of the shared assembly.

Important 

Publisher policy files only apply to shared assemblies installed into the global assembly cache.

To set up publisher policies we have to:

  • Create a publisher policy file

  • Create a publisher policy assembly

  • Add the publisher policy assembly to the global assembly cache

Create a Publisher Policy File

A publisher policy file is an XML file that redirects an existing version or version range to a new version. The syntax used is the same as for application configuration files, so we can use the same file we created earlier to redirect the old versions 1.0.0.0-1.0.999.99999 to the new version 1.1.741.31355.

I renamed the previously created file to mypolicy.config to use it as a publisher policy file.

   <?xml version="1.0"?>     <configuration>     <runtime>     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">     <dependentAssembly>     <assemblyIdentity name="SimpleShared"     publicKeyToken="be9f9ce7b9a0a62f" />     <bindingRedirect oldVersion="1.0.0.0-1.0.999.99999"     newVersion="1.1.741.31355" />     </dependentAssembly>     </assemblyBinding>     </runtime>     </configuration>   
Create a Publisher Policy Assembly

To associate the publisher policy file with the shared assembly we have to create a publisher policy assembly that can be put into the global assembly cache. The tool that can be used to create such files is the assembly linker al . The option /linkresource adds the publisher policy file to the generated assembly. The name of the generated assembly must start with policy, followed by the major and minor version number of the assembly that should be redirected, and the filename of the shared assembly. In our case the publisher policy assembly must be named policy.1.0.SimpleShared.dll to redirect the assemblies SimpleShared with the major version 1, and minor version 0. The key that must be added to this publisher key with the option / keyfile is the same key that was used to sign the shared assembly SimpleShared to guarantee that the version redirection is from the same publisher.

  al /linkresource:mypolicy.config /out:policy.1.0.SimpleShared.dll  /keyfile:..\..\mykey.snk 
Add the Publisher Policy Assembly to the Global Assembly Cache

The publisher policy assembly can now be added to the global assembly cache with the utility gacutil .

  gacutil i policy.1.0.SimpleShared.dll  

Now we can remove the application configuration file that was placed in the directory of the client application, and start the client application. Although the client assembly references 1.0.741.29127 we use the new version 1.1.741.31355 of the shared assembly because of the publisher policy.

Overriding Publisher Policies

With a publisher policy, the publisher of the shared assembly guarantees that a new version of the assembly is compatible with the old version. As we know from changes of traditional DLLs, such guarantees don't always hold. Maybe all but one application is working with the new shared assembly. To fix the one application that has a problem with the new release, we can override the publisher policy by using an application configuration file.

With the .NET Framework configuration tool we can override the publisher policy by setting a checkbox:

click to expand

Disabling the publisher policy with the .NET Framework Configuration results in a configuration file with the XML element < publisherPolicy > and the attribute apply="no" .

 <?xml version="1.0"?> <configuration>   <runtime>     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">       <dependentAssembly>         <assemblyIdentity name="SimpleShared" publicKeyToken="be9f9ce7b9a0a62f" />   <publisherPolicy apply="no" />   </dependentAssembly>     </assemblyBinding>   </runtime> </configuration> 

Disabling the publisher policy we can configure different version redirection in the application configuration file.

Fixing an Application

If it happens that an application doesn't run because a configuration is wrong or because newly installed assemblies let it fail, the .NET Framework Configuration has an option to fix .NET applications. Clicking the Fix an Application hyperlink lists all .NET applications that were running previously and allows us to restore the last version of the application configuration file. With the Advanced option, it is also possible to reapply a specific configuration that probably was working, as can be seen in the screenshot opposite . Selecting the Application SafeMode disables publisher policies.

click to expand

Runtime Version

In an application configuration file, it's not only possible to redirect versions of referenced assemblies; we can also define the required version of the runtime. Different .NET runtime versions can be installed on a single machine. We can specify the version that's required for the application in an application configuration file:

   <?xml version="1.0"?>     <configuration>     <startup>     <requiredRuntime version="v1.0.3512" safeMode="true" />     </startup>     </configuration>   

The version attribute of the < requiredRuntime > element specifies the version number of the runtime. The version number must be the same name as the directory of the runtime. The runtime I'm using is in the directory c:\winnt\Microsoft.NET\Framework\v1.0.3512 , so the version I have to specify is v1.0.3512 .

Configuring Directories

We've already seen how to redirect referenced assemblies to a different version so that we can locate our assemblies, but there are more options to configure! For example, it's not necessary to install a shared assembly in the global assembly cache. It's also possible that shared assemblies can be found with the help of specific directory settings in configuration files. This feature can be used if you want to make the shared components available on a server. Another possible scenario is if you want to share an assembly between your applications, but you don't want to make it publicly available in the global assembly cache, so you put it into a shared directory instead.

There are two ways to find the correct directory for an assembly: the codeBase element in an XML configuration file, or through probing. The codeBase configuration is only available for shared assemblies, and probing is done for private assemblies.

<codeBase>

The < codeBase > can also be configured using the .NET Admin Tool. Codebases can be configured by selecting the properties of the configured application, SimpleShared , inside the Configured Assemblies in the Applications tree. Similar to the Binding Policy , we can configure lists of versions with the Codebases tab. In the following screen we have configured that the version 1.0 should be loaded from the Web server http://CNagel/WroxUtils :

click to expand

The .NET Admin tool creates this application configuration file:

   <?xml version="1.0"?>     <configuration>     <runtime>     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">     <dependentAssembly xmlns="">     <assemblyIdentity name="SimpleShared"     publicKeyToken="6ca9587197f6f8c2" />     <codeBase version="1.0" href="http://CNagel/WroxUtils" />     </dependentAssembly>     </assemblyBinding>     </runtime>     </configuration>   

The < dependentAssembly > element is the same used previously for the version redirection. The < codeBase > element has the attributes version and href . With version , the original referenced version of the assembly must be specified. With href , we can define the directory from where the assembly should be loaded. In our example, a path using the HTTP protocol is used. A directory on a local system or a share is specified using href="file:C:/WroxUtils" .

When using that assembly loaded from the network a System.Security.Permissions exception occurs. You must configure the required permissions for assemblies loaded from the network. In Chapter 23 we show how to configure security for assemblies.

<probing>

When the < codeBase > is not configured and the assembly is not stored in the global assembly cache, the runtime tries to find an assembly with probing . The .NET runtime tries to find an assembly with either a . dll or a . exe file extension in the application directory, or in a subdirectory thereof, that has the same name as the assembly searched for. If the assembly is not found here, the search continues. You can configure search directories with the < probing > element in the < runtime > section of application configuration files. This XML configuration can also be done easily by selecting the properties of the application with the .NET Framework Configuration tool. We can configure the directories where the probing should occur by using the search path:

click to expand

The XML file produced has these entries:

 <?xml version="1.0"?> <configuration>    <runtime>       <gcConcurrent enabled="enabled" />       <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">   <probing privatePath="bin;utils;" xmlns="" />   </assemblyBinding>    </runtime> </configuration> 

The < probing > element has just a single required attribute: privatePath . This application configuration file tells the runtime that assemblies should be searched for in the base directory of the application, followed by the bin and the util directory. Both directories are subdirectories of the application base directory. It's not possible to reference a private assembly outside the application base directory or a subdirectory thereof. An assembly outside of the application base directory must have a shared name and can be referenced using the < codeBase > element as we've done before.

  


Professional C#. 2nd Edition
Performance Consulting: A Practical Guide for HR and Learning Professionals
ISBN: 1576754359
EAN: 2147483647
Year: 2002
Pages: 244

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