12

I'm trying to use AppDomain.AssemblyResolve event to handle exceptions while resolving Assemblies of some dll loaded at runtime (SerializationException for dynamically loaded Type).

When the event is fired, I load all DLLs in my directory and create an Assembly array, then I use this method to get the Assembly containing the type I specify:

public static Assembly GetAssemblyContainingType(String completeTypeName, 
                                                 Assembly[] assemblies)
{
    Assembly assembly = null;

    foreach (Assembly currentassembly in assemblies)
    {
        Type t = currentassembly.GetType(completeTypeName, false, true);
        if (t != null)
        {
            assembly = currentassembly;
            break;
        }
    }

    return assembly;
}

The problem is that this code works only with an AssemblyQualifiedName, and the ResolveEventArgs.Name provided by the event is not so useful.

Can you suggest me some workaround?

Is there a way to pass some other arguments to the event when it is fired?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
davioooh
  • 23,742
  • 39
  • 159
  • 250

2 Answers2

19

You can define a dictionary of the assemblies from your directory, like this:

private readonly IDictionary<string,Assembly> additional =
    new Dictionary<string,Assembly>();

Load this dictionary with the assemblies from your known directory, like this:

foreach ( var assemblyName ... corresponding to DLL names in your directory... ) {
    var assembly = Assembly.Load(assemblyName);
    additional.Add(assembly.FullName, assembly);
}

Provide an implementation for the hook...

private Assembly ResolveAssembly(Object sender, ResolveEventArgs e) {
    Assembly res;
    additional.TryGetValue(e.Name, out res);
    return res;
}

...and hook it up to the event:

AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += ResolveAssembly;
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;

This should do the trick.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 5
    Doesn't preloading the assemblies obviate the need for an AssemblyResolve event handler? – Mike Zboray Feb 07 '12 at 18:02
  • 4
    @mikez As far as I know, simply loading an assembly using the `Assembly.Load(assemblyName)` does not automatically make it available to the assembly resolution code of your application domain (unless that code can access the assembly using the default resolution process). This code is lifted from a working system (I removed error handling code, e.g. around the `additional.TryGetValue(e.Name, out res)` call to simplify things a bit). When I remove the `ResolveAssembly` hook, my working system stops working :) – Sergey Kalinichenko Feb 07 '12 at 18:16
  • 8
    When you're building the dictionary, use AssemblyName.GetAssemblyName() instead of Assmebly.Load to get the assembly name to filename mappings and avoid unconditionally loading all of the assemblies. – Simon Brangwin May 02 '12 at 23:15
0

If you know list of assemblies that may contain type you are planning to deserialize it could be better to simply pre-load all assemblies before doing serialization.

When AssemblyResolve event is fired you have no information about what type caused the load, but only assembly name. It is unclear why you would look up assembly by some particular type in this case.

Note that if 2 assemblies happen to have the same identity (i.e. file name in non-strongly-signed case) and one is already loaded event will not fire when you expect even if type is not found in already loaded assembly.

Link to the article for historical purposes: Resolving Assembly Loads.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • As you can also read in my old question http://stackoverflow.com/q/9158353/1061499 I'm working on an application that uses a plug-in approach to load various application of an interface at run time. When the application is closed I need to serialize these objects, then when the application is re-launched these objects must be de-serialized. The problem is that the object types are loaded at run-time, so their type is not resolved... – davioooh Feb 09 '12 at 08:50