.NET Framework Side-by-Side Execution


So far in this guide we have looked at the relatively simple situation where applications are installed in isolation. There is no assumption that other applications will already exist on computers. However, in many cases you are likely to have multiple .NET-based applications running alongside each other. Those applications may share assemblies, and in some cases you may find that they require different versions of the same assembly in order to run properly. Not only that, but applications may even be build on different versions of the Framework and may not function properly using another runtime.

Fortunately, one of the major benefits of the Framework is the ability to run multiple applications, using multiple versions of the same components, requiring multiple versions of the runtime itself. This functionality is known collectively as side-by-side execution.

The following illustration shows several applications using two different versions of the runtime on the same computer. Applications A, B, and C use runtime version 1.0, while application D uses runtime version 1.1.

click to expand
Figure 4.5: Side-by-side execution of two versions of the runtime

The .NET Framework consists of the common language runtime and about two dozen assemblies that contain the API types. The runtime and the .NET Framework assemblies may have different versions. For example, version 1.0 of the runtime is actually version 1.0.3705.0, while version 1.0 of the .NET Framework assemblies is version 1.0.3300.0.

Running Assemblies Side by Side

Prior to Windows XP and the .NET Framework, DLL conflicts occurred because applications were unable to distinguish between incompatible versions of the same code. Type information contained in a DLL was bound only to a file name. An application had no way of knowing if the types contained in a DLL were the same types that the application was built with. As a result, a new version of a component would often overwrite an older version and break applications. Side-by-side execution of the .NET Framework provides a number of features to eliminate DLL conflicts.

Determining Which Assembly to Load

In order to understand how assemblies can exist side by side, it is important to know how the CLR determines which assembly to load. This will depend on a whole series of factors, including whether the assembly is strong named, how the assembly is referenced in the application which calls it, and where the assembly is located.

For detailed information on how assemblies are loaded, see "How the Runtime Locates Assemblies" on MSDN.

There are a number of ways in which you can notify the CLR to load an updated version of a strong named assembly. These include:

  • Updating the application configuration file

  • Use a publisher policy

  • Updating the machine configuration file

We will discuss each of these in turn:

Application Configuration File

You can instruct the CLR to load an updated version by providing binding redirects in your application's configuration file. You must then deploy not only the updated strong-named assembly, but also the updated application configuration file that contains the binding redirect information. The following code snippet shows an example of redirecting your application to use an updated assembly:

 <configuration>   <runtime>     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">       <dependentAssembly>          <assemblyIdentity name="myAssembly" publicKeyToken="32ab4ba45e0a69a1"                                         culture="en-us" />          <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/>       </dependentAssembly>     </assemblyBinding>   </runtime> </configuration> 

Note

The CLR attempts to locate assemblies in the global assembly cache before searching in the application base folder. Consequently, if you deploy a strong-named private assembly with your application, but it is already present in the global assembly cache, the CLR uses the shared version, rather than the private one, at run time. This should not lead to any problems, because assemblies with the same strong name should always be identical.

Publisher Policy

You can state that applications should use a newer version of an assembly by supplying a publisher policy file with the upgraded assembly. The publisher policy, which contains assembly redirections, is itself located in an assembly, and placed in the global assembly cache. If a publisher policy file exists, the runtime checks this file after checking the assembly's manifest and application configuration file. You should use publisher policies only when the new assembly is backward compatible with the assembly being redirected.

Note

New versions of assemblies that claim to be backward compatible can still break specific applications. When this happens, you can use the following setting in the application configuration file to make the runtime bypass the publisher policy: <publisherPolicy apply="no">.

You can create a publisher policy file to specify assembly redirection for upgraded versions of strong-named assemblies. A publisher policy file is an XML document that is similar to an application configuration file. You need to compile it into a publisher policy assembly and place it in the global assembly cache for it to take effect.

  • To create and deploy a publisher policy

    1. Create a publisher policy file.

    2. Create a publisher policy assembly from your publisher policy file, using the Assembly Linker utility (AL.exe).

    3. Add your strong-named shared assembly to the appropriate location.

    4. Add the publisher policy assembly to the global assembly cache.

For more information about publisher policy files, see Creating a Publisher Policy File on MSDN:

Machine Configuration File

You can also redirect assembly versions with the machine configuration file. Unlike application settings, when determining binding redirects, the machine configuration file is checked after the application configuration file. This means that the machine configuration file overrides all of the individual application configuration files and publisher policies, and applies to all applications. As a result you do not often use the machine configuration file to store this information. However, there might be some cases when you want all of the applications on a computer to use a specific version of an assembly. For example, you might want every application to use a particular assembly version because it fixes a security hole. If an assembly is redirected in the machine configuration file, all of the applications using the earlier version will use the later version.

For more information about redirecting assembly binding, see "Redirecting Assembly Versions" on MSDN.

Isolation

Using the .NET Framework, you can create applications and components that execute in isolation, an essential component of side-by-side execution. Isolation involves being aware of the resources you are using and safely sharing resources between multiple versions of an application or component. Isolation also includes storing files in a version-specific way.

Assemblies in the Global Assembly Cache

Placing assemblies in the global assembly cache produces some significant benefits for side-by-side operations. These include:

  • The global assembly cache supports side by side installation of multiple versions of a single component. Assemblies installed in an application directory can not support side by side since the directory can only contain one file of a given name and all versions of a component share the same file name.

  • You can control the precise binding semantics used for code in the global assembly cache.

  • Individual applications can choose to bind to any version of an assembly in the global assembly cache. Multiple applications can each bind to different versions of the same assembly in the global assembly cache.

After an assembly is installed into the global assembly cache, you cannot simply copy a new version and have your application use that updated assembly. As with all strong-named assemblies, applications contain the strong name (complete with version number) of the assembly that they reference in their own manifests. Instead of simply copying a new version of the strong-named assembly, you can either recompile against the newer version or provide binding redirection for the referencing application as well.

Version-Aware Code Storage

The .NET Framework provides version-aware code storage in the global assembly cache. The global assembly cache is a computer-wide code cache present on all computers with the .NET Framework installed. It stores assemblies based on version, culture, and publisher information, and supports multiple versions of components and applications residing in the same location. Unless specified elsewhere, each application will use the version of the assembly it used at compile time.

Testing Considerations for Side-by-Side Shared Assemblies

Although the Framework is designed to allow assemblies to run side by side without problems, whether they can do so or not will depend in part on how the assemblies were designed. Therefore there are a number of areas you should test to show that you are able to deploy the assemblies successfully side by side.

You should ensure that your installs (and uninstalls) work as expected. For example, if a registry key is created during the install of an assembly, and a second version of that assembly is installed that requires the same registry key, you need to determine how install and uninstall routines should behave with respect to that registry key. For this example, you want to ensure that the registry key is not removed if either assembly version is uninstalled, because this will break the remaining version.

You will also need to ensure that side-by-side execution works properly. For example, if multiple versions of an assembly rely on a registry key or any shared resource (such as a file, directory, and so on) and both versions are executing side by side, you will need to determine how the assemblies affect each other. You need to ensure that changes to shared resources by one version of the assembly will not adversely affect the other version(s).

Furthermore, if more than one version of an assembly is used by a process, you will need to determine if there are type issues. For example, let's say that you have an assembly which has had both version 1 and 2 installed into the global assembly cache. Now imagine that two controls are used in one application, and that one control references version 1 and the other control references version 2 of your assembly. You need to determine whether the assemblies can be used together in the same application in this way. The types in the different assemblies are considered to be different by the common language runtime, and so cannot be exchanged.

Running Distributed Applications Side by Side

If your application is designed to run across multiple physical computers, versioning issues are complicated as you may have different versions of the Framework installed on different computers. It is therefore very important to thoroughly test any updates to your application on a distributed environment that matches your production environment.

For More Information on side by side issues for Distributed applications, see "Side-by-Side and Versioning Considerations for .NET Remoting" on MSDN.

Running Multiple Versions of the Framework Side by Side

Versions 1.0 and 1.1 of the .NET Framework are designed to be compatible. A properly configured application built with the .NET Framework version 1.0 should run on version 1.1, and a properly configured application built with the .NET Framework version 1.1 can be configured to work with version 1.0 of the Framework, and should function with no problems, unless it refers to API features that were added in version 1.1.

Note

For more information on compatibility changes to the .NET Framework see, "Backwards Breaking Changes from version 1.0 to 1.1" on the GotDotNet Web site.

Versions of the .NET Framework are treated as a single unit consisting of the runtime and its associated .NET Framework assemblies (a concept referred to as assembly unification). You can redirect assembly binding to include other versions of the .NET Framework assemblies, but overriding the default assembly binding can be risky and must be rigorously tested before deployment.

Determining Which Version of the Runtime to Load

The runtime determines the available runtime versions by enumerating the keys and values in the registry under HKLM\SOFTWARE\Microsoft\.NETFramework\policy. Each key identifies the major and minor version of the runtime. The values under each major and minor key identify the build number. For example, the key HKLM\SOFTWARE\Microsoft\.NETFramework\policy\v1.1 with a value of 4322 indicates that version 1.1.4322 of the .NET Framework is installed.

A directory with the same version number as specified in the registry must also exist under the .NET Framework installation root. The directory names are preceded with the letter v. For example, version 1.1.4322 of the .NET Framework would be installed in <WinDir>\ Microsoft.NET\Framework\v1.1.4322\ where <WinDir> is the Windows directory.

The following are the .NET Framework versions currently available:

  • Version 1.0 is v1.0.3705

  • Version 1.1 is v1.1.4322

The runtime uses the both the application configuration file and the PE file header to determine which versions of the runtime are supported by the application. Assuming an application configuration file is present, the following process is used to determine the appropriate runtime version to load:

  1. The runtime examines the <supportedRuntime> element in the application configuration file. If one or more of the supported runtime versions specified in the <supportedRuntime> element are present, the runtime loads the runtime version specified by the first <supportedRuntime> element. If this version is not available, the runtime examines the next <supportedRuntime> element and attempts to load the runtime version specified. If this runtime version is not available, subsequent <supportedRuntime> elements are examined. If none of the supported runtime versions are available, the runtime fails to load a runtime version and displays a message to the user (see step 4). See the .NET Framework General Reference on this topic for more information.

  2. If no <supportedRuntime> element is present, the runtime examines the <requiredRuntime> element in the application configuration file. This element is used only for runtime version 1.0 applications. If the runtime version specified by the <requiredRuntime> element is present, the runtime loads it. If the specified version is not available, the runtime fails to load a runtime version and displays a message to the user (see step 4). If the application configuration file has no <requiredRuntime> element, the process continues to step 3. See the .NET Framework General Reference on this topic for more information.

  3. The runtime reads the PE file header of the application's executable file. If the runtime version specified by the PE file header is available, the runtime loads that version. If the runtime version specified is not available, the runtime searches for a runtime version determined by Microsoft to be a suitable replacement for the runtime version in the PE header. If that version is not found, the process continues to step 4.

  4. The runtime displays a message stating that the runtime version supported by the application is unavailable. The runtime is not loaded. If this process is conducted for a service or some other event that does not involve user interaction, and you have set the HKLM\Software\Microsoft\.NETFramework\NoGuiFromShim registry key to 1, then the message is written to the Event Log.

Note

After a runtime version is loaded, assembly binding redirects can specify that a different version of an individual .NET Framework assembly be loaded. These binding redirects affect only the specific assembly that is redirected.

Running .NET-based Applications with Dependencies

In some cases you may find that you have an application compiled under one version of the Framework, but a dependent dll compiled under another. Of course this is not necessary, as it is possible to run multiple versions of DLLs on the same computer, and in the case of the global assembly cache, the same location. Add to that the fact that unless you specify otherwise the DLL used will be the one used at compile time, and you will see that having applications where there is this kind of discrepancy is fairly unusual.

However there are circumstances in which this kind of situation could arise. For example, an old version of a DLL could be removed for security reasons and existing applications simply reconfigured to use the new one. Under these circumstances the application determines which version of the Framework is run (only one version can run at a time for a particular application) and the dependent DLL has to attempt to run under that version.

The following table shows the behavior of a .NET-based application with a dependent DLL where different versions of the application, component, and Framework are available.

Table 4.3: Side by Side Behavior of a Window Forms-based Application

Application Version

Only .NET Framework v1.0 installed

Only .NET Framework v1.1 installed

Both versions of the Framework installed

Application v1.0

Component v1.0

No issues with compatibility

It will attempt to run with the v1.1 CLR[1]

Will run with v1.0 of the Framework

Application v1.0

Component v1.1

Will run under the v1.0 CLR[2]

It will attempt to run with the v1.1 CLR[1]

Will run with v1.0 of the Framework

Application v1.1

Component v1.0

Will run under the v1.0 CLR[3]

It will attempt to run with the v1.1 CLR[1]

Will run with v1.1 of the Framework[1]

Application v1.1

Component v1.1

Will run under the v1.0 CLR[3]

No issues with compatibility

Will run with v1.1 of the Framework

[1]Could break if any of the components are using functionality that has been broken in the new version of the Framework. For more information on the list of break points in the functionality, please see the link at the end of this chapter.

[2]Could break if the components are using v1.1 APIs as they are not supported in the earlier version.

[3]This is true if the <supportedRuntime> element is used, otherwise it will send an error.

Configuring a COM Application for Side-by-Side Execution

Application configuration files enable a COM application to bind to a specific managed component and specify which version of the runtime runs the component. COM application developers can create a .NET-based application configuration file and deploy it with their applications.

Managed and unmanaged applications use the identical configuration file schema to specify a version of the runtime and to bind to a specific component.

Specifying the Runtime Version

If a COM application calls managed code without an application configuration file, the latest compatible runtime version installed on the computer is loaded by default. If this behavior does not satisfy the requirements of your COM application, you should indicate in a configuration file specific runtime versions that your application requires. For example, you can specify runtime version 1.1.4322, which loads the .NET Framework version 1.1.

  • To specify runtime version 1.1.4322

    1. Using an XML editor, create an application configuration file.

    2. Insert the following standard header at the beginning of the file:

       <?xml version ="1.0" encoding = "utf-8"> Insert the following XML elements into the file: <configuration>    <startup>        <supportedRuntime version="v1.1.4322"/>    </startup> </configuration> 

    Note

    COM components hosted by an extensible host, such as Microsoft Internet Explorer or Microsoft Office cannot control which version of the runtime is loaded. However, you can create an application configuration file for the host application which will determine which version of the runtime is used.

Specifying an Assembly Version

If a COM application calls a .NET assembly without using an application configuration file, the runtime loads the latest version of the assembly registered in the Windows registry that contains the type to be activated from COM. You can override this behavior by directing your application to bind to an earlier assembly version.

  • To redirect assembly binding to an earlier version

    1. Using an XML editor, create an application configuration file.

    2. Insert the following standard header at the beginning of the file:

       <?xml version="1.0" encoding="utf-8" ?> 

    3. Insert the following XML elements into the file. The <bindingRedirect> element with the oldVersion and newVersion attributes redirects binding for myManagedAssembly version 2.0 to version 1.0. For more information on the <bindingRedirect> element, see the .NET Framework General Reference.

       <configuration>    <runtime>       <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">          <dependentAssembly>             <assemblyIdentity name="myManagedAssembly"                               publicKeyToken="32ab4ba45e0a69a1"                               culture="en-us" />             <bindingRedirect oldVersion="2.0.0.0"                              newVersion="1.0.0.0"/>          </dependentAssembly>       </assemblyBinding>    </runtime> </configuration> 

    4. You can redirect more than one assembly version by including multiple <bindingRedirect> elements within a <dependentAssembly> element. For more information on the <dependentAssembly> element, see the ".NET Framework General Reference."

Side-by-Side Issues with Serviced Components

As you update your serviced components, or if you have a scenario where multiple versions of the same component are on the same computer, you can encounter several issues caused by having these components installed side by side. To help you maintain your serviced components, you should adhere to the following advice:

  • Do not use globally unique identifiers (GUIDs) as the GuidAttribute class or ApplicationIDAttribute. Instead use the ApplicationNameAttribute. If you do use a GUID, you need to hard code the GUID into the assembly, which requires you to manually change this GUID if you update your component and have it run alongside the original version; otherwise, the COM+ installation overwrites the settings for the earlier version.

  • Remember that assembly versioning applies only to the assemblies themselves, not the COM+ application. There is no automatic way to version the application itself. If the newer version of a serviced component requires changes at the COM+ application level that will break previous versions of the component, then you need to use the application name to indicate versioning by installing the newer version of the serviced component into its own COM+ application.

For more information about serviced components, see "Understanding Enterprise Services (COM+) in .NET" on MSDN.

ASP.NET Applications Running Side-by-Side

The .NET Framework allows you to install multiple versions of the runtime on the same computer. By default, when the .NET Framework is installed on a computer with an existing installation, all ASP.NET applications are automatically updated to use this version of the .NET Framework. The only exceptions are applications that are bound to an incompatible version of the runtime or to a later version of the runtime. Although later versions of the .NET Framework are designed to be backwards compatible, you might want to configure an ASP.NET application to use an earlier version.

Script Maps for ASP.NET Applications

When multiple versions of the .NET Framework are installed on the same computer, each installation contains an associated version of the ASP.NET ISAPI (aspnet_filter.dll). An ASP.NET application uses the ASP.NET ISAPI to determine which version of the .NET Framework to use for the application. An ASP.NET application can be configured to use any of the installed ASP.NET ISAPI versions. To specify the ASP.NET ISAPI version to use for an ASP.NET application, a script map is registered in IIS for the application.

A script map associates a file extension and HTTP verb with the appropriate ISAPI for script handling. For example, when IIS receives a request for an .aspx file, the script map for the application directs IIS to forward the requested file to the appropriate version of the ASP.NET ISAPI for processing. The script map for each ASP.NET application is normally set in the IIS management console and can be applied directly to an application, or inherited from a parent application. By default, when the .NET Framework is installed, the script maps for all existing ASP.NET applications on the computer are automatically updated to use the ASP.NET ISAPI version associated with the installation, unless the application uses a later or an incompatible version.

To make it easier to reconfigure the script map for an ASP.NET application, each installation of the .NET Framework comes with an associated version of the ASP.NET IIS Registration tool (Aspnet_regiis.exe). By default, this tool is installed in the following directory:

<windir>\Microsoft.NET\Framework\versionNumber

Administrators can use this tool to remap an ASP.NET application to the ASP.NET ISAPI version associated with the tool.

Note

Because Aspnet_regiis.exe is associated with a specific version of the .NET Framework, administrators must use the appropriate version of Aspnet_regiis.exe to reconfigure the script map for an ASP.NET application. Aspnet_regiis.exe only reconfigures the script map of an ASP.NET application to the ASP.NET ISAPI version associated with the tool.

The tool can also be used to display the status of all installed versions of ASP.NET, register the associated version of ASP.NET, create client-script directories, and perform other configuration operations.

For more information about script maps and IIS configuration, see the documentation for IIS.

For more information on updating script maps for an ASP.NET application, see the "Configuring an ASP.NET Application for an ASP.NET Version" on MSDN.

Using Application Center to Manage Side-by-Side Instances

Although not limited to ASP.NET deployments, Application Center is useful at deploying ASP.NET applications and can make side-by-side deployment easier. Therefore, when deploying upgraded server applications to your cluster, you should consider using Application Center to implement side-by-side application instances. Side-by-side application instances allow you to retain an existing version of your application while you deploy a new version to the production environment and verify that it functions as expected. The following scenario explains how this works.

Imagine the application you need to upgrade has been installed into a folder called CommerceApp2001, and that this application has been deployed to all members of your cluster to implement a Web farm. Rather than directly upgrade this application and have it synchronized across your cluster, you can install your upgraded application into a different folder, for example, CommerceApp2002, and create a new virtual directory that maps to this folder.

You can have this new virtual directory synchronized across your cluster and the application located in CommerceApp2001 will not have been modified and will continue to handle requests from clients. At this stage, you will have two versions of the application both able to function in the production environment. You can then verify that the application in CommerceApp2002 functions as expected in the real production environment, and you might consider advertising to selected customers the fact that your application has been upgraded by informing them of the URL for the new application. They can then provide you with valuable feedback on your upgraded application before you release it to a wider audience.

When you are satisfied that the solution functions as expected and you are confident that you can release it for use by all clients, you can perform the following simple operations:

  • Modify the virtual directory settings on your cluster controller so that your original application now references the CommerceApp2002 folder, rather than CommerceApp2001.

  • Synchronize your application across the cluster — the mapping between virtual directory and local folder is stored in the IIS metabase and this setting will be replicated from the cluster controller to the other cluster members.

If it becomes necessary to revert to the original version, rolling back this change is simply a matter of setting the virtual directory to CommerceApp2001 and then Application Center will synchronize the change across the cluster.

For more information about implementing your specific deployment scenarios with Application Center, see "Best Practices for Phased Deployment Using Application Center 2000."

Security Considerations

Each installation of the .NET Framework has a separate security configuration file, there are no forward or backward compatibility issues with security settings. However, if your application depends on the additional security capabilities of ADO.NET included in the .NET Framework version 1.1, you will not be able to distribute it to a version 1.0 system.

ASP.NET and Dependent Components

As with Windows Forms-based applications, there are circumstances where you may have an ASP.NET application and a dependent component compiled on different versions of the Framework. Unlike Windows-based applications the Framework itself will not be existing side by side, as the version used will be defined at the virtual directory or Web level. The following table shows how the application and component will behave in these circumstances.

Table 4.4: Side by Side of an ASP.NET Application

Application Version

Only .NET Framework v1.0

Only .NET Framework v1.1

Application v1.0

Component v1.0

No issues with compatibility

It will attempt to run with the v1.1 CLR[1]

Application v1.0

Component v1.1

Will run under the v1.0 CLR[2]

It will attempt to run with the v1.1 CLR[1]

Application v1.1

Component v1.0

Will run under the v1.0 CLR[3]

It will attempt to run with the v1.1 CLR[1]

Application v1.1

Component v1.1

Will run under the v1.0 CLR[3]

No issues with compatibility

[1]Could break if any of the components are using functionality that has been broken in the new version of the Framework. For more information on the list of break points in the functionality, please see the link at the end of this chapter.

[2]Could break if the components are using v1.1 APIs as they are not supported in the earlier version.

[3]This is true if the <supportedRuntime> element is used, otherwise it will send an error.




Deploying. NET Applications Lifecycle Guide
Deploying .NET Applications: A Lifecycle Guide: A Lifecycle Guide (Patterns & Practices)
ISBN: B004V9MSJW
EAN: N/A
Year: 2003
Pages: 53

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