Работа с событием AppDomain.AssemblyResolve

Я пытаюсь использовать событие AppDomain.AssemblyResolve для обработки исключений при разрешении сборок некоторых dll, загруженных во время выполнения (SerializationException для динамически загружаемого типа ).

Когда событие запускается, я загружаю все библиотеки DLL в свой каталог и создаю массив Assembly, затем я использую этот метод, чтобы получить Assembly, содержащий указанный мной тип:

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;
}

Проблема в том, что этот код работает только с AssemblyQualifiedName, а ResolveEventArgs.Name, предоставляемый событием, не так полезен.

Можете ли вы предложить мне обходной путь?

Есть ли способ передать некоторые другие аргументы событию при его запуске?


person davioooh    schedule 07.02.2012    source источник


Ответы (2)


Вы можете определить словарь сборок из вашего каталога, например:

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

Загрузите этот словарь со сборками из известного вам каталога, например:

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

Предоставьте реализацию для хука...

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

... и подключите его к событию:

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

Это должно сработать.

person Sergey Kalinichenko    schedule 07.02.2012
comment
Разве предварительная загрузка сборок не устраняет необходимость в обработчике событий AssemblyResolve? - person Mike Zboray; 07.02.2012
comment
@mikez Насколько мне известно, простая загрузка сборки с использованием Assembly.Load(assemblyName) не делает ее автоматически доступной для кода разрешения сборки вашего домена приложения (если этот код не может получить доступ к сборке с использованием процесса разрешения по умолчанию). Этот код взят из работающей системы (я удалил код обработки ошибок, например, вокруг вызова additional.TryGetValue(e.Name, out res), чтобы немного упростить ситуацию). Когда я удаляю хук ResolveAssembly, моя рабочая система перестает работать :) - person Sergey Kalinichenko; 07.02.2012
comment
При создании словаря используйте AssemblyName.GetAssemblyName(‹assemblyFile›) вместо Assmebly.Load, чтобы получить сопоставление имени сборки с именем файла и избежать безусловной загрузки всех сборок. - person Simon Brangwin; 03.05.2012

Если вы знаете список сборок, которые могут содержать тип, который вы планируете десериализовать, может быть лучше просто предварительно загрузить все сборки перед сериализацией.

Когда запускается событие AssemblyResolve, у вас нет информации о том, какой тип вызвал загрузку, а есть только имя сборки. Непонятно, зачем в этом случае искать сборку по какому-то определенному типу.

Обратите внимание, что если две сборки имеют одинаковую идентичность (т. е. имя файла в случае без строгой подписи), а одна из них уже загружена, событие не сработает, когда вы ожидаете, даже если тип не найден в уже загруженной сборке.

Ссылка на статью для исторических целей: Разрешение загрузки сборок.

person Alexei Levenkov    schedule 07.02.2012
comment
Как вы также можете прочитать в моем старом вопросе stackoverflow.com/q/9158353/1061499, я работаю над приложением, которое использует подключаемый модуль для загрузки различных приложений интерфейса во время выполнения. Когда приложение закрыто, мне нужно сериализовать эти объекты, а затем, когда приложение перезапускается, эти объекты должны быть десериализованы. Проблема в том, что типы объектов загружаются во время выполнения, поэтому их тип не разрешается... - person davioooh; 09.02.2012