This
article describes how the CLR locates and binds assemblies and how to change
the default behavior when needed (e.g. in the deployment stage).
Any
developer and system administrator who deals with .NET assemblies, especially
commercial applications, must be familiar with these topics. This knowledge is
the best way to plan for service packs, upgrades and hot fixes as they come
along.
The
.NET Framework is loaded (almost inflated) with a bunch of terms and features
related to assembly deployment, locating and binding.
Here
is a short list:
·
Static and dynamic
loading
·
Public and private
·
GAC and private folder
·
Probing
·
Codebase
·
BindingRedirect
·
App.Config and Machine.config
·
Strongly named and
weakly named
·
DevelopmentMode
Audience
The
article is not at the beginner level, readers with basic knowledge in
configuration files and assembly structure can also benefit from it right in
the first reading.
The quest for type resolving
The
CLR – Common Language Runtime – is responsible for the process of locating and
binding referenced assemblies. Locating is the process of finding the correct
assembly in the hard disk. Binding is the process of loading the assembly in
the application address space.
The
quest begins when the JIT encounters user defined types that need to be
resolved. Then the CLR tries to detect where the type definition is:
·
Same file in the same
assembly
·
Different file in the
same assembly
·
Different assembly
This
article deals with the third option.
General process blocks
The
CLR moves from stage to stage, as described above, in order to determine the
exact assembly to load. The reason for this flow is that each stage might
override the information in the previous stage. Although, it might look like a
cry out redundancy it is really necessary, because of the need to make changes
in the deployment files after installation. For example, when installing a
Service Pack, the system administrator would like to keep the previous
installation up and running. This need requires changes in the locating and the
binding process of new assemblies with new versions.
1)
Search for referenced assembly upon name and version
1.
Configuration File - App.config
The
CLR checks the App.config after
the manifest check. In case the referenced assembly version is overridden the App.config setting has the upper hand.
2.
Publisher policy file
The
CLR checks for the publisher policy file after the App.config check. Publisher policy files are
deployed as part of an update, hot fix or service pack. A publisher policy file
is used when the updated shared/public assembly has a new version (that it is
different from the assembly's manifest). The setting in the publisher policy
file has the upper hand unless the App.config file
sets the safe mode ( ).
3.
Machine configuration file
The
CLR checks in the machine.config file after the
publisher policy file check. The file is shared by all .NET applications on the
machine. In case of a version difference, the setting in the Machine.config has the upper hand.
2)
Checking for previously referenced assemblies
The
CLR checks if the assembly is already loaded (due to previous code execution
statements). If found the CLR uses it. At first it looks like the fox in
Redmond has a design bug - why not checking the assembly in the previous loaded
assembly list in the first stage? The reason for that is the need to examine first
which version is required.
3)
Check in the GAC (Global Assembly Cache)
If
not found in stage 2 and the manifest implies that the assembly is strongly
named, the CLR checks the GAC. If exists, the GAC has the upper hand.
4)
Codebase or Probing
The
prior stages inform the CLR what is the required assembly version. In this
stage, the CLR attempts to find and load the assembly.
1.
Codebase
If
the Codebase tag is defined
in the application configuration file, the CLR checks only the defined
location. If the assembly is not in the given URL, the probing process is
terminated.
2.
Probing
In
case there is no Codebase tag in the configuration file or if the attempt to
retrieve the file from the URL fails, the CLR starts the Probing process.
3.
Subdirectories
Search
in the application directory and then in the subdirectories with the assembly
name.
[application base] / [assembly name].dll
[application base] /
[assembly name] / [assembly name].dll
If
the referenced assembly has a culture definition then the CLR checks in the
following sub-directories:
[application base] /
[culture] / [assembly name].dll
[application base] /
[culture] / [assembly name] / [assembly name].dll
The
CLR also check in BinPath.
Tip: The CLR terminates
the probing process as soon as the reference assembly is found (name search
only). In case the assembly is correct - all is well - else the binding fails
(Filenotfound exception
raised).
Features and Terms
Static
and Dynamic loading
In
static loading, the CLR checks for assemblies in the assembly manifest. The
list of statically referenced assemblies is entered to the file in the build
process. In dynamic loading, the CLR is introduced to the assembly in
run time. This feature is wrapped up in the System.Reflection assembly,
which exposes methods like Assembly.Load (similar
to the LoadLibrary function).
Private
and Public/Shared assemblies
Shared
assemblies are not deployed in the same directory of the application that uses
them. The CLR will not complain if you do, but it is a deployment error to copy
the shared assembly in one of the base application's directory and direct
others to it. Typically shared assemblies are registered in the GAC or in a
share directory (the application that uses them needs to know about).
Strongly
and weakly named assemblies
The
main difference between the two is that a strongly named assembly contains a
public token. The token uniquely identifies the assembly. It is required for
shared assemblies that are installed in the GAC. The reason for that is the
slight chance that some developer creates an assembly with the same name,
culture and version as one that happens to be installed in the same PC. Another
difference (implied from the previous) is that strong name assemblies can be
deployed privately and publicly (GAC) whereas weakly named assemblies can only
be deployed privately.
Tip: Do not copy the
assembly to the GAC folder ([windows main folder]\assembly). The assembly must be registered in the GAC. Use the
GacUtil via the .NET command prompt or drag and drop the assembly to the GAC
window.
Shared assembly and the GAC
A
shared assembly that is copied outside the application base directory must be
strongly named but is not required to be installed in the GAC. In this case the
shared assembly location must be specified in the configuration file using the Codebase tag. Application
suites can create a shared folder and copy the shared assemblies to it.
The
following is a list of reasons that helps to decide when to use the GAC instead
of a proprietary shared folder:
·
Third party
applications might use the shared assembly. Copying the assemblies to a shared
folder obligates the application that uses them to know about its location.
·
Side by side execution
is easier when new version assemblies are installed in the GAC. It saves the
time of dealing with different paths for different versions. Moreover, using
proprietary, shared folders might cause DLL Hell.
·
Only a user who is
defined in the Windows administration group can install assemblies in the GAC
(security).
·
Shared folder is more
accessible for reckless user mistakes like delete and override.
·
Save disk storage:
this is quite a stupid reason - I know. Today, disks are very cheap, but you cannot
ignore the fact that copying an assembly to different locations over and over
again will have some storage impact.
Probing
This
is one of the two ways to define an assembly location. The instruction is done
in a configuration file. You can specify only subdirectories under the
application base directory
CodeBase
This
is one of the two ways to define an assembly location. The CLR, first checks
the assembly version, then searches for an override CodeBase definition
in the configuration file. The version attribute is required, only, for strong
named assemblies. For weakly named assemblies the href attribute
must be assigned, only, to a subdirectory. This URL can refer to a directory on
the user's hard disk or to a Web address. In the case of a Web address, the CLR
will automatically download the file and store it in the user's download cache
(a subdirectory under \\Local Settings\Application Data\Assembly ).
When referenced in the future, the CLR will load the assembly from this
directory rather than access the URL. The CodeBase tag should
only be defined in the machine configuration or publisher policy files that
also redirect the assembly version.
BindingRedirect
This
feature enables the binding of a certain assembly to a different file version
and it is very useful for service pack installations. Usually the redirect is
done to a GAC registered assembly. The GAC allows us to install the same
assembly with different versions. The CLR checks the configuration file and
redirects the binding accordingly.
Locating
Assemblies Using DEVPATH
The DEVPATH is nice
feature for the development stage. The feature eases the development life cycle
by delaying the decisions in regards to the deployment stage.
The developer can create a DEVPATH environment
variable that points to the build output directory for the assembly. Follow
these steps to enjoy this feature:
·
Specify
the element in the machine configuration file. Make sure you add it to the
relevant framework version.
The CLR searches for the referenced assemblies in the
path described in the DEVPATH environment
variable.
·
Define an environment
variable. Name: DEVPATH. Value: path. Make sure that you
enter it as a system variable and that the path value is ending with \.
Example: add the following statement above the
tag.
</configuration>
<runtime>
<developmentMode developerInstallation="true"/>
</runtime>
</configuration>
Snippets
The
snippets below are related to the following example:
·
The application name
is HelloWorld.
·
The application is
located in c:\MyTest.
·
ProductCabinet is a sub directory under the MyTest directory (c:\MyTest\ProductCabinet).
·
The file ReferencedFile.dll is located under the ProductCabinet directory.
version="1.0" encoding="utf?8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas?microsoft?com:asm.v1">
<probing privatePath=" ProductCabinet" />
</assemblyBinding>
</runtime>
</configuration>
version="1.0" encoding="utf?8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas?microsoft?com:asm.v1">
<dependentAssembly>
<codeBase version="1.0.0.0"
href= "file:///c:\
MyTest\ProductCabinet ReferencedFile.dll"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
version="1.0" encoding="utf?8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name=" ReferencedFile"
publicKeyToken="99ab3ba45e0b54a8"
culture="en-us" />
<bindingRedirect oldVersion="1.0.0.0"
newVersion="2.0.0.0"/>
</dependentAssembly>
<publisherPolicy apply="no">
</assemblyBinding>
</runtime>
</configuration>
___________________________________________________________________
Reach us At: - 0120-4029000; 0120-4029024; 0120-4029025,
0120-4029027; 0120-4029029



No comments:
Post a Comment