Neuere Assemblys laden, ohne Binding-Redirects in der App.Config-Datei


#1

Manchmal ist es in Windows-.NET-Anwendungen (Konsole, WinForms, WPF, usw.) lästig, immer Binding-Redirects in seiner Anwendungs-Konfigurations-Datei mitzugeben.

Abhilfe schafft hier das AssemblyResolve-Ereignis, so wie in dieser Stack-Overflow-Antwort beschrieben.

Meine Code dazu:

static class Program
{
    private static readonly IDictionary<string, Assembly> _additional =
        new Dictionary<string, Assembly>();

    static void Main()
    {
        // --
        // http://stackoverflow.com/a/9180843/107625

        var dir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
        foreach (var assemblyName in Directory.GetFiles(dir, @"*.dll"))
        {
            var assembly = Assembly.LoadFile(assemblyName);
            _additional.Add(assembly.GetName().Name, assembly);
        }

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

        // --

        // ... Hier kommt der eigentliche Programmcode ...

    }

    // 
    private static Assembly CurrentDomain_ResolveAssembly(
        object sender, 
        ResolveEventArgs e)
    {
        // Hier mache ich quasi mein eigenes, automatisches, Binding-Redirect.
        // (z.B. Newtonsoft.Json 6.0.0.0 nach 9.0.0.0).

        var name = e.Name.Substring(0, e.Name.IndexOf(','));

        _additional.TryGetValue(name, out var res);
        return res;
    }
}

Je nach Programmart, in der obiger Code verwendet wird, kann es nötig sein, das Laden der Assemblies in einen try-catch-Block zu packen.

Also anstatt:

var assembly = Assembly.LoadFile(assemblyName);
_additional.Add(assembly.GetName().Name, assembly);

Dann eher:

try
{
    var assembly = Assembly.LoadFile(assemblyName);
    _additional.Add(assembly.GetName().Name, assembly);
}
catch (BadImageFormatException) // TODO: Ggf. noch weitere Exception-Typen auffangen.
{
    // Ignorieren.
}

Der Grund ist, dass z. B. auch nicht-.NET-DLLs im Programmordner liegen können, und diese dann beim Laden fehlschlagen.