Assembly Binding

So far we have learned that assembly bindings can be redirected using either the application configuration file, the machine configuration file, or the publisher policy. In addition, a referenced assembly can be located in either the GAC, the application local directory, or any of its subdirectories as dictated by the privatePath entry in the configuration file. This complexity makes you wonder if there is any order that the assembly resolver follows to bind to an assembly. Adding to this complexity is the fact that an assembly can automatically be downloaded and installed based on the codeBase entry in the configuration file. Fortunately, there is a method to the madness.

Let's first recap how an assembly gets loaded in an application. There are two ways:

  1. When the application tries to access a type defined in a referenced assembly, and the assembly has not already been loaded. These references are called static references. Recall that static references are recorded in the application's manifest.

  2. When the application explicitly loads an assembly using methods such as Assembly.Load, Assembly.LoadFrom, or Assembly.LoadWithPartialName. Such references are called dynamic references.

Deferred Loading of Assemblies

Under .NET, a referenced assembly does not get loaded until the application tries to access a type defined in the assembly. It is entirely possible, for example, to run an application even though a referenced assembly is missing. As long as the current execution path does not access a type from the missing assembly, the application runs as expected.

Contrast this to linking with import libraries in the case of non-.NET applications. If a linked DLL cannot be found when the application is started, the execution aborts in the start-up phase itself.


Irrespective of the way an assembly is loaded, the assembly resolver uses the same algorithm for binding to the assembly. Note that the assembly name to be loaded need not always be fully specified; in this case it is referred to as a partial reference.

The assembly resolver initiates a bind in the following order:

  1. The assembly resolver determines from the input the name and culture (if any) of the assembly to load. In addition, for loading strong-named assemblies, the resolver determines the correct assembly version to load by examining the publisher policy (if any), the machine configuration file, and the application configuration file (if any). The settings in the publisher policy are overridden by the settings in the machine configuration file. The settings in the machine configuration file are overridden by the settings in the application configuration file. If the specified assembly is not strong-named, the version number is ignored.

  2. If the requested assembly has already been loaded (as a result of a previous request), the resolver binds to the assembly that is already loaded.

  3. For strong-named full references (non-null public key token) or if Assembly.LoadWithPartialName is called, the resolver checks the GAC. If the assembly is found, the resolver binds to this assembly.

  4. For strong-named references (full or partial), the resolver probes the codeBase entry in the configuration files. If the entry is found, the resolver downloads the assembly and binds to it. If the download fails for some reason, the resolver determines that the binding request has failed. No further probing occurs.

  5. Finally, the runtime probes the application's base directory, followed by other subdirectories specified in the privatePath entry of the configuration file(s). If the reference contains culture information, the runtime also looks into the subdirectory that matches the culture string.

If the assembly bind is unsuccessful, the runtime throws the familiar FileLoadException.

Assembly Binding Log Viewer

If the assembly bind is unsuccessful, the runtime writes the information to a log file. The framework provides a tool called the Assembly Binding Log Viewer (Fuslogvw.exe) that can be used to examine the log file and obtain details about a specific failure. This is an important tool that can save hours of frustration.


Let's pause for a moment and briefly recap what we have learned so far. An assembly is a basic unit of versioning and deployment. It consists of MSIL code, type metadata, the manifest, and resources. An assembly can either be private to an application or can be installed in the GAC. When loading an assembly, the assembly resolver goes through a series of steps to locate and bind to the assembly.

An important feature of the type metadata under .NET is that it is extensible. Using attributes, you can add extra information to any element of your code in a nonprogrammatic way. The attribute information gets saved in the assembly, thus making the assembly completely self-describing. Attribute-based programming is so pervasive under .NET that it deserves special attention. Let's take a look at this style of programming.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.161.132