At build time, development tools record dependency information for each assembly that is referenced. This information is kept in the assembly manifest as AssemblyRefs. A key element of an AssemblyRef is the compatibility version number of the dependent assembly. The NGWS runtime uses these version numbers to load the proper version of an assembly at runtime.
The Assembly Resolver distinguishes between private and shared assemblies for the purposes of versioning. Specifically, no version checking is done when resolving references to private assemblies – the description of version checking described in this document applies only to references to shared assemblies.
The philosophy behind not checking versions on private assemblies is that such assemblies are authored by the same person or organization that produced the application that uses the assembly. Therefore, the private assembly is deployed along with the app and is placed in the same directory as the app, or a subdirectory thereof. In other words, the app author has control over the contents and distribution of the assembly.
The distinction between a reference to a private assembly verses a shared assembly is the presence of an Originator in the reference. The Originator is the public key used to give the assembly a shared name. All references to shared assemblies, i.e the reference contains an Originator, follow the version checking rules described in this document regardless of where they are deployed.
Note that it is possible to reference a shared assembly, but not provide the Originator in the reference. In this case, the Assembly Resolver will follow the binding rules for private assemblies.
The manifest records the compatibility version number of each dependency at the time your assembly was compiled. However, in many cases, it may be acceptable to run with different versions of the assemblies than those present at build time. For example, even if version 5 of a dependency was present at build time, a more recent version may be acceptable at runtime. The rules that specify the acceptable versions of an assembly are called version policies. Again, all version policies are based on the compatibility version number, not the informational version. Version polices are expressed using the <BindingPolicy> tag in the configuration files. Configurations can also be used to change version policy if a particular version of a dependency causes an application to stop working. In this case, a configuration can be used to "roll back" to the specific version of a dependency that was present at build time.
The NGWS runtime supports the following version policies:
The default version policy is to take the version of the dependent assembly that is recorded in the manifest and match major and minor numbers exactly then take the latest build and revision numbers.
Mapping back to the semantic parts of the version number described above, the default policy binds to the exact “incompatible” version, then looks in the global assembly cache for the latest “maybe_compatible” and “QFE” versions. For example, if the Assembly Resolver is given a reference to version 5.0.11.0, and a version 5.0.11.12 is present in the assembly cache, version 5.0.11.12 will be returned.
A few points about this default policy are worth stressing. First the “use latest” behavior described above only applies to the build and revision portions of the compatibility version number. The policy of taking the latest build and revision is often referred to as Automatic QFE Policy. This QFE policy allows software vendors to release critical bug fixes without requiring dependent applications to be rebuilt or reconfigured. It is worth noting that this policy is implicit in that there is nothing that the NGWS runtime does to enforce that a "QFE" is in fact backward compatible with the version it is replacing. We never implicitly take the latest major and minor numbers because they are, by definition, incompatible with what is being requested.
Second, the Assembly Resolver only looks in the global assembly cache for QFE’s. If a search path is specified through configuration, the Assembly Resolver DOES NOT look at all assemblies on the path searching for the one with the highest build and revision number. The performance cost of doing so is prohibitive.
There are times where it may be desirable to bind to a different version of an assembly than the version recorded in the manifest. Support for this scenario is provided through the <BindingPolicy> tag in the configuration files. This policy can be used to map either references to a specific version of a dependency or references to all versions of a dependency.
The following example maps references to all versions of an assembly called calcr to version 6.0.0.0:
<BindingPolicy> <BindingRedir Name="Calcr" Originator="32ab4ba45e0a69a1" Version="*" VersionNew="6.0.0.0" UseLatestBuildRevision="yes"/> </BindingPolicy>
The two policies described so far both employ automatic QFE policy. There are clearly times where this is not desirable. For example, consider the scenario where an administrator installs a bug fix release (QFE) to a shared assembly that ends up working for most applications, but breaks others. In this scenario, the administrator would like to disable the automatic QFE policy for those applications that have broken because of the update. The support for this scenario is also in the <BindingPolicy> tag. BindingPolicy has an attribute called UseLatestBuildRevision that can be set to “no” to disable automatic QFE policy for references to a particular assembly. For example, the following XML snippet binds all references to calcr to exactly version 6.1.1212.14 – no QFE’s to that version will be picked up:
<BindingPolicy> <BindingRedir Name="Calcr" Originator="32ab4ba45e0a69a1" Version="*" VersionNew="6.1.1212.14" UseLatestBuildRevision="no"/>
</BindingPolicy>
Safe mode is the version policy used to ensure that the versions of the assemblies that were built and tested together are the same versions that are run together after they are deployed. If an application passed tests and worked correctly prior to deployment, the safe mode version policy can be used to revert to this known state in the presence of failures caused by running with incompatible (or just buggy) versions of dependent assemblies. Safe mode always applies to an entire application, not to individual assembly references. To get similar behavior for a particular reference use <BindingPolicy> to bind to a particular version and turn off automatic QFE policy.
When running with the safe mode policy, the Assembly Resolver ignores any other version policies and binds to exactly the version of the dependent assembly that is recorded in the manifest. All four parts of the version number are checked to ensure an exact match – no QFE’s are applied.
Safe Mode is turned on using the <BindingMode> tag in the configuration files. The following XML snippet turns on Safe Mode for an application:
<BindingMode> <AppBindingMode Mode="safe"/> </BindingMode>