# Thursday, October 26, 2006
« Developer Night in Canada Interview | Main | Assembly Identity Concept »

The CLR loader offers a few APIs for loading assemblies, each of which have a slightly different model and behaviour for how they go about the task. I'd like to cover those and hopefully set folks on the best path for using loading assemblies.

The APIs that I have in mind are:

  • Assembly.Load(), and
  • Assembly.LoadWithPartialName()

First, you need to understand the concepts of fully-specified and partial assembly names.  A fully specified name contains the following parts: the simple name, version, culture, and public key or public key token. A partial name contains at least the simple name and optionally any of the other parts of the full-specified name. This concept is most relevant to the textual identity of an assembly. For example, here is the fully-specified assembly textual identity for v2.0 System.dll: "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089". The textual identity is a specially formatted string that is used to describe some or all of the aspects of identifying an assembly.

Assembly.Load() takes a string as one of the overloads. The textual identity, as you see formatted above, is just the sort of string that Load() is expecting. Load() also takes other types, such as AssemblyName, but that's not important for the moment. The textual identity can be fully or partially specified, and which one it is has an important impact on the way that these loader APIs operate. The one you see above for System.dll is fully specified, since all the parts are there. Note that there is an additional part (or attribute) of the textual indentity that I've missed -- ProcessorArchitecture -- but that complicates the discussion too much for not much benefit, so I'm not going to cover it here.

The following bit of code shows the use of these APIs with full- and partially-specified names. The comments inline should pretty well explain what to expect

using System;
using System.Reflection;

namespace BindingByIdentity
{
class Program
{
static void Main(string[] args)
{
Assembly asm;

//LoadWithPartialName() looks in both the appbase and the GAC, looking for the best match,
//where "best match" isn't very clearly defined
//In addition, this method has been deprecated, which means "don't use this anymore, and it may be removed later"
try
{
Console.WriteLine("Calling LoadWithPartialName");
asm = Assembly.LoadWithPartialName("System");
Console.WriteLine("Loaded: {0}",asm.FullName);
}
catch(Exception e)
{
Console.WriteLine("LoadWithPartialName threw with the following exception:");
Console.WriteLine(e.Message);
}


//Load() with a partial name looks only in the appbase
//There is no gaurantee that you will get the assembly that you want
//In the case that you have private bin paths specified, there are no order gaurantees
//This particular use of the Assembly.Load() will always throw, since this assembly will not be found (because it is GAC'd)
try
{
Console.WriteLine("Calling Load");
asm = Assembly.Load("System, PublicKeyToken=b77a5c561934e089");
Console.WriteLine("Loaded: {0}", asm.FullName);
}
catch(Exception e)
{
Console.WriteLine("Load threw with the following exception:");
Console.WriteLine(e.Message);
}

//Load() with a fully-specified name looks in the appbase and the GAC and gaurantees that you
//will get the assembly that you asked for
try
{
Console.WriteLine("Calling Load");
asm = Assembly.Load("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
Console.WriteLine("Loaded: {0}", asm.FullName);
}
catch (Exception e)
{
Console.WriteLine("Load threw with the following exception:");
Console.WriteLine(e.Message);
}


}
}
}

Output:

Calling LoadWithPartialName
Loaded: System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Calling Load
Load threw with the following exception:
Could not load file or assembly 'System, PublicKeyToken=b77a5c561934e089' or one
 of its dependencies. The system cannot find the file specified.
Calling Load
Loaded: System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

The moral of this story is that Assembly.LoadWithPartialName() is always bad and shouldn't be used since its behaviour isn't well-defined or predictable, and that you should always fully-specify the textual identity strings that you pass into Assembly.Load(). It may be the case that partially specified strings "work" since the assemblies you are attempted to load are always going to be in the app-base, but the fully-specified names do make your code and your intentions more clear, particularly for the next guy that has to look at the code you wrote. The funny thing is that sometimes "the next guy" is you, just two months later ;)

There is also the case that your code might not be strong-named. You should still specify everything but the publickey/token in that case.

Thursday, October 26, 2006 7:43:59 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  |