Подтвердить что ты не робот

Assembly.GetTypes() - ReflectionTypeLoadException

Мы реализуем платформу плагинов для нашего приложения и загружаем сборки плагинов с помощью Assembly.Loadfrom. Затем мы используем GetTypes() и дополнительно изучаем типы с каждым файлом плагина для поддерживаемых интерфейсов.

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

Мы создаем две версии программного обеспечения из одной базы кода (appA_1 и appA_2).

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

Базовая версия нашего кода:

var pluginAssembly = Assembly.LoadFrom(FileName);    
foreach (var pluginType in pluginAssembly.GetTypes())
{

Мы получаем исключение "ReflectionTypeLoadException".

Это связано с тем, что мы хотим, чтобы наше приложение могло загружать типы любого плагина, созданного кем-либо. Что-то нам не хватает?

EDIT: После итерации через LoaderExceptions мы обнаружили, что существует один файл libPublic.dll, который генерирует исключение System.IO.FileNotFoundException. Странно, что этот файл находится в каталоге приложения, а плагин ссылается на файл проекта.

ИЗМЕНИТЬ 2: В журнале исключений мы находим следующее "Сравнение названия сборки привело к несоответствию: номер версии"

4b9b3361

Ответ 1

Несколько вещей:

  • Удостоверьтесь, что у вас нет дубликатов сборок в каталоге плагинов (т.е. сборок, которые вы уже загрузили в своем основном приложении из каталога вашего приложения.) В противном случае при загрузке вашего плагина он может загрузить дополнительную копию той же сборки. Это может привести к забавным исключениям, например:

    Объект (типа "MyObject" ) не относится к типу "MyObject".

  • Если вы создаете исключение при создании экземпляра типа, вам может потребоваться обработать AppDomain.AssemblyResolve:

    private void App_Startup(object sender, StartupEventArgs e)
    {
        // Since we'll be dynamically loading assemblies at runtime, 
        // we need to add an appropriate resolution path
        // Otherwise weird things like failing to instantiate TypeConverters will happen
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    }
    
    private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        var domain = (AppDomain) sender;
    
        foreach (var assembly in domain.GetAssemblies())
        {
            if (assembly.FullName == args.Name)
            {
                return assembly;
            }
        }
    
        return null;
    }
    

Я понимаю, что немного странно говорить CLR, что для того, чтобы разрешить сборку, найдите сборку с именем, которое мы используем для разрешения, но я видел странные вещи без этого. Например, я мог бы создавать типы из сборки плагинов, но если бы я попытался использовать TypeDescriptor.GetConverter, он не нашел бы TypeConverter для класса, хотя мог бы видеть атрибут Converter в классе.


Глядя на ваши изменения, это, вероятно, не то, что вызывает ваше текущее исключение, хотя вы можете столкнуться с этими проблемами позже, когда работаете со своими плагинами.

Ответ 2

Благодаря этому сообщению я смог решить ReflectionTypeLoadException, который я получал в UITypeEditor. Это сборка конструктора (интеллектуальный тег winforms, используемый во время разработки) библиотеки пользовательских классов, которые сканируют некоторые типы.

/// <summary>
/// Get the types defined in the RootComponent.
/// </summary>
private List<Type> getAssemblyTypes(IServiceProvider provider)
{
    var types = new List<Type>();
    try
    {
        IDesignerHost host = (IDesignerHost)provider.GetService(typeof(IDesignerHost));
        ITypeResolutionService resolution = (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService));
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            foreach (var assembly in ((AppDomain)sender).GetAssemblies())
            {
                if (assembly.FullName == args.Name)
                {
                    return assembly;
                }
            }

            return null;
        };

        Type rootComponentType = resolution.GetType(host.RootComponentClassName, false);
        types = rootComponentType.Assembly.GetTypes().ToList();
    }
    catch
    {
    }

    return types;
}

Ответ 3

Вы получаете несоответствие версии сборки. Поскольку ваши плагины относятся к этому libPublic.dll, вы должны тщательно его модифицировать и, в частности, не удалять его версию/сборку/etc. числа при каждом компиляции.