When an assembly needs to be loaded into an AppDomain, the .NET CLR will look in all sorts of places before giving up and throwing a FileNotFoundException in your face. Actually I've always been impressed with how well this part of the CLR works, being able to just drop files into directories without having to change code, re-directing bindings and dictating how the CLR should deal with newer versions of an assembly through configuration files, etc.

There are situations however, where this built-in functionality is not enough. In those cases you need to provide some custom logic for resolving a reference to an assembly and you can do this using the AppDomain.AssemblyResolve event. When the CLR fails to resolve an assembly reference, it will fire this event as a last resort hoping that someone will do the hard work and locate the assembly for it. The arguments of the event provide you with the full name of the assembly in question, which you need to use to determine which assembly to use. This is a tremendously flexible solution, but there are some things to watch out for

  • Make sure that for a specific full name, you always provide the CLR with a reference to the same assembly. If you don't you will experience some very weird issues (failing to cast being one of them) which will be difficult to trace back to this piece of code.
  • If you build this logic into an assembly you are possibly limiting its re-usability. Because this is an event and not a method that can be overridden, there is no way of stopping it from being executed unless you provide the CLR with the assembly through the usual means.
  • When you have multiple dependencies between assemblies, things can get tricky. Tim Weaver felt this pain recently.
  • If you load an assembly either from disk or from memory (i.e. Assembly.Load(byte[])) in the event handler of the AppDomain.AssemblyResolve event, the CLR (actually Fusion) doesn't keep track of it. This means that the second time the same assembly is needed, although you might have already loaded the assembly into the current AppDomain, the AppDomain.AssemblyResolve event will be fired again! You need to implement your own caching mechanism to avoid loading the same assembly into the same AppDomain multiple times (which of course will result in plenty of errors that initially make little sense).
Suzanne Cook has a nice post on Assembly identity that is relevant to the last bullet point here