AssemblyResolve Event

CLR uses documented heuristics to probe assemblies. If assembly can’t be found through the standard heuristics, CLR will raise an AssemblyResolve event. You can subscribe AssemblyResolve event to provide the assembly in the case assembly can’t be found through standard probing. This is the way (and the only way in v1/v1.1) to implement a custom assembly loader.

If your application is multi-threaded, your event handler may be called from many different threads simultaneously. In that case, your event handler has to be thread-safe.

The ResolveEventArgs has a Name property, which tells you which assembly CLR is expecting. It is very important that you always return the same assembly for the same Name. Otherwise you may encounter the Assembly Identity problem.

Comments (11)

  1. Luc Cluitmans says:

    I have been playing around with the AssemblyResolve event a few months ago and I was somewhat surprised that I had to implement my own caching and keeping-track-of of loaded assemblies. Wrestling with bugs caused by doubly-loaded assemblies is not fun… Why doesn’t the system walk the list of already loaded assemblies before firing AssemblyResolve? The only reason I can think of is that for some reason doubly loaded Assemblies are not a bug, but a feature. Are there any examples around that explore the possiblities of this?

    Another point: You mention "This is the way (and the only way in v1/v1.1) to implement a custom assembly loader". Does that mean there are alternatives in v2 of the framework? Could you provide a bit more information about that?

  2. CLR does walk the list of already loaded assemblies before firing AssemblyResolve. I am not expert on this. I’ll ask Suzanne to take a look.

    The second question, there will be more information when v2 beta1 is released. I can’t disclose unpublished stuff yet.

  3. Luc Cluitmans says:

    Thanks for the answer.

    A small followup on the first question:

    The problem is that, as far as my understanding goes, only the assemblies loaded through Fusion are walked, and the very reason you got an AssemblyResolve event is of course that fusion was unable to find the assembly.

    Of course you could handle the event in a way that makes the assembly findable by Fusion (e.g. downloading it onto the search path), but in my case I was responding to AssemblyResolve by calling the Assembly.Load versions that take byte arrays (because my target assemblies were not files themselves, but were embedded in other files), and as far as I know those are not tracked by Fusion.

    As far as I know this whole system is rather underdocumented, so I don’t know any more about it than what can be extracted from blogs like Suzanne’s.

  4. I agree the documentation is rather weak on this. Suzanne’s and my blog( and many others) are trying fill the hole between implementation and documentation. Many things are implementation detail, and can’t be documented properly ( since it may change at the next version).

  5. Nicholas Allen says:

    When does the system loader forget that an assembly has been found with a given name? Is it kept for the application lifetime or does eliminating all uses of an assembly allow the binding to be removed?

  6. It is kept by the lifetime of the appdomain, unless the assembly happens to be loaded as domain neutral, in which case it is per application lifetime.

  7. Nicholas Allen says:

    Ok thanks, that’s good to know. Having to create separate AppDomains adds to the application design burden, but is a workable solution for reloading assemblies during runtime.

  8. Suzanne Cook says:

    Luc: Yes, it is a feature. However, the AssemblyResolve event is meant as a last resort, for those who want to do something special (ought to be a rare case).

    Of course, I don’t know the details of what you’re doing, but I usually recommend avoiding such implementations. I can imagine a case where you would need to do this to work around a limitation imposed on you. But, if possible, it would be cleaner to have the assemblies be standalone, not embedded; then, using the event is unnecessary.

    Junfeng’s comment really refers to an implementation detail. Conceptually, the only caching is in the LoadFrom context. See .

    We’re already working on beefing up the MSDN documentation in this area.