Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
Топик располагается на нескольких страницах: 1 2      [все]
 Reflection не отдупляет  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72766
Пытаюсь сделать систему плагинов.
Проект 1 - набор интерфейсов и статический класс, перебирающий dll'ки в поисках классов, реализующих эти интерфейсы. Перебирает таким способом:

        private static readonly Dictionary<string, IPlugin> _plugins = new Dictionary<string, IPlugin>();

        public static Dictionary<string, IPlugin> RequestPlugins(IApiFactory factory)
        {
            foreach (var file in Directory.GetFiles(Directory.GetCurrentDirectory()))
            {
                if (file.Substring(file.Length - 4).ToLower() != ".dll")
                    continue;
                try
                {
                    var ass = Assembly.LoadFrom(file);
                    var plugType = ass.GetExportedTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).FirstOrDefault();
                    if (plugType == null)
                        continue;
                    IPlugin plugin = Activator.CreateInstance(plugType, factory) as IPlugin;
                    _plugins.Add(plugin.Id, plugin);
                }
                catch (Exception) {
                }
            }
            return _plugins;
        }


Проект 2 - потребитель плагинов, дергает RequestPlugins.
Проект 3 - плагин, один из классов которого реализует IPlugin.

2 и 3 зависят от 1, и не зависят друг от друга. 1 ни от кого не зависит.

Пока 3 лежит в отдельной папке, всё работает, а как только перемещается в bin проекта 2 - перестает. Обнаружил, что в точке останова внутри вышеуказанной процедуры TypeHandle у typeof(IPlugin) и plugType.ImplementedInterfaces[0] (если вручную присвоить plugType из GetExportedTypes, IsAssignableFrom перестает работать) - разные, то есть с точки зрения 1 и 3 IPlugin, который 1 предоставляет, а 3, соответственно, реализует - это разные IPlugin'ы. Соответственно и CreateInstance перестает работать - IApiFactory тоже становятся разными, возникает ошибка о том, что подходящий конструктор не найден.

Почему это происходит и как победить?
28 ноя 18, 18:48    [21747802]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Cat2
Member

Откуда: Petroskoi, Karjala
Сообщений: 145636
Antonariy,

Exception какой?

У меня подозрение на строку
_plugins.Add(plugin.Id, plugin);

Возможно вылетает при попытке вставить неуникальный plugin.Id?
28 ноя 18, 18:56    [21747808]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Antonariy,
Попробуй без linq на циклах отладить.
28 ноя 18, 19:15    [21747826]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
fkthat
Member

Откуда:
Сообщений: 1163
Зачем велосипеды? Есть ведь MEF.
28 ноя 18, 19:21    [21747831]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Cat2
Member

Откуда: Petroskoi, Karjala
Сообщений: 145636
fkthat
Зачем велосипеды? Есть ведь MEF.

А что это за зверь, в двух словах?
28 ноя 18, 19:25    [21747833]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
mikron
Member

Откуда: Germany / Stuttgart
Сообщений: 798
Antonariy,

1. LoadFrom уже не верно. Надо ReflectionOnlyLoad.
2. Оставь это рукоблудие, используй System.ComponentModel.Composition
28 ноя 18, 19:33    [21747837]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
fkthat
Member

Откуда:
Сообщений: 1163
Cat2
fkthat
Зачем велосипеды? Есть ведь MEF.

А что это за зверь, в двух словах?


"Managed Extensibility Framework". Несложная приблуда (осваивается за час), специально, чтобы лепить приложения с плагинами.
28 ноя 18, 19:42    [21747844]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Cat2
Member

Откуда: Petroskoi, Karjala
Сообщений: 145636
fkthat
Cat2
пропущено...

А что это за зверь, в двух словах?


"Managed Extensibility Framework". Несложная приблуда (осваивается за час), специально, чтобы лепить приложения с плагинами.

Приложения с платинами или плагины к приложениям?
28 ноя 18, 19:50    [21747849]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
fkthat
Member

Откуда:
Сообщений: 1163
Cat2
Приложения с платинами или плагины к приложениям?



Приложения, в которые ты хочешь встроить свою систему плагинов.
28 ноя 18, 19:54    [21747852]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Cat2
Member

Откуда: Petroskoi, Karjala
Сообщений: 145636
fkthat
Cat2
Приложения с платинами или плагины к приложениям?


Приложения, в которые ты хочешь встроить свою систему плагинов.

Спасибо. Страшно далек я от плагинов и ничего о них не знаю Картинка с другого сайта.
28 ноя 18, 20:00    [21747858]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Cat2
Member

Откуда: Petroskoi, Karjala
Сообщений: 145636
Petro123
Antonariy,
Попробуй без linq на циклах отладить.

+1
28 ноя 18, 20:04    [21747865]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
fkthat
Member

Откуда:
Сообщений: 1163
Antonariy
IPlugin, который 1 предоставляет, а 3, соответственно, реализует - это разные IPlugin'ы.


Чисто, в порядке мозгового штурма - может что-то не так с версиями сборок? Типа 3 собрана с какой-то другой версией 1, чем та, с которой собрана 2.
28 ноя 18, 20:19    [21747877]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72766
Petro123
Antonariy,
Попробуй без linq на циклах отладить.
linq тут вообще ни при чем, я же написал, что в ручном режиме не работает.

fkthat
Зачем велосипеды? Есть ведь MEF.
Хрень какая-то. В демонстрационном солюшене вынес интерфейсы в отдельный проект как у меня, перевел на него зависимости, и все перестало работать: "Не удалось загрузить тип "SimpleCalculator3.IOperation" из сборки "SimpleCalculator3". Вот же тупой Composition, не может по строчке new AssemblyCatalog(typeof(IOperation).Assembly) догадаться, в какой сборке лежит IOperation.

mikron
1. LoadFrom уже не верно. Надо ReflectionOnlyLoad.
ок

fkthat
Чисто, в порядке мозгового штурма - может что-то не так с версиями сборок?
Нет, меняется только командная строка в событиях после сборки, которая копирует собранную длл в ту или иную папку. Копируешь в bin основного проекта - не пашет, копируешь в любую другую папку - пашет.
29 ноя 18, 00:07    [21747959]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Antonariy
Petro123
Antonariy,
Попробуй без linq на циклах отладить.
linq тут вообще ни при чем, я же написал, что в ручном режиме не работает.
мы же код текущий смотрим.
Приведи код ручного режима и исключение на строке.
Если до сих пор не работает.
29 ноя 18, 07:05    [21748004]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Arm79
Member

Откуда: МО, Раменское
Сообщений: 3669
>> file.Substring(file.Length - 4).ToLower() != ".dll"
Path.GetExtension

>> var ass = Assembly.LoadFrom(file);
Так делать некомильфо. Загруженный плагиг уже не выгрузить. Обычно создают отдельный AppDomain и грузят в него. И когда возникает надобность выгрузить ненужный плагин без перезапуска ПО, выгружают весь AppDomain

И уже правильно рекомендовали: MEF. Более сложная штука, но более устойчивая с сбоям - MAF.
29 ноя 18, 09:28    [21748059]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Arm79
Member

Откуда: МО, Раменское
Сообщений: 3669
>> Directory.GetFiles(Directory.GetCurrentDirectory())
Вы уверены, что такая конструкция верно с вашей точки зрения определяет текущую папку? Попробуйте явно задать путь, в целях отладки.

>> Обнаружил, что в точке останова внутри вышеуказанной процедуры TypeHandle ... разные
А какие?
29 ноя 18, 09:33    [21748064]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72766
Arm79
Так делать некомильфо. Загруженный плагиг уже не выгрузить.
не требуется

Arm79
А какие?
TypeHandle это число, какая разница, какие конкретно значения? Важно лишь то, что в разных папках они одинаковые, а в одной - отличаются. И это как-то указывает на причину проблемы, но пока не ясно как.
29 ноя 18, 09:47    [21748080]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72766
Antonariy
mikron
1. LoadFrom уже не верно. Надо ReflectionOnlyLoad.
ок
не катит, зависимые сборки не грузятся, сваливается в ошибку.

короче:

            var ass = Assembly.LoadFrom("Plugin.dll"); // текущая папка - bin
            var plug = ass.GetExportedTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).FirstOrDefault();
не работает
            var ass = Assembly.LoadFrom(Directory.GetCurrentDirectory() + "..\plugins\Plugin.dll");
            var plug = ass.GetExportedTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).FirstOrDefault();
работает
29 ноя 18, 10:19    [21748126]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Arm79
Member

Откуда: МО, Раменское
Сообщений: 3669
Arm79
>> Directory.GetFiles(Directory.GetCurrentDirectory())
Вы уверены, что такая конструкция верно с вашей точки зрения определяет текущую папку? Попробуйте явно задать путь, в целях отладки.

Antonariy
var ass = Assembly.LoadFrom(Directory.GetCurrentDirectory() + "..\plugins\Plugin.dll");
            var plug = ass.GetExportedTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).FirstOrDefault();

работает


Накидал по быстрому проект, работает:

+ Основное приложение
    class Program
    {
        static void Main(string[] args)
        {
            var pls = PluginLoader.LoadPlugins(Directory.GetCurrentDirectory());

            foreach(var pl in pls)
            {
                pl.DoSmth("plugin call");
                pl.DoSmth("plugin call");
                pl.DoSmth("plugin call");
            }

            Console.ReadLine();
            
        }
    }



+ Общая сборка с интерфейсом
    public interface IPlugin
    {
        string Id { get; }
        void DoSmth(string txt);
    }

    public static class PluginLoader
    {
        public static IReadOnlyCollection<IPlugin> LoadPlugins(string path)
        {
            var result = new List<IPlugin>();
            var potencialPlugins = Directory.GetFiles(path, "*.dll");

            foreach (string item in potencialPlugins)
            {
                if (Path.GetFileName(item) == "PluginCommon.dll")
                    continue;

                Assembly ass = Assembly.LoadFrom(item);
                List<Type> targetTypes = ass.GetExportedTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).ToList();

                if (targetTypes.Count == 0)
                    continue;

                foreach (Type pluginType in targetTypes)
                    result.Add((IPlugin) Activator.CreateInstance(pluginType));
            }

            return result.AsReadOnly();
        }
    }


+ Две разные сборки с классами-наследниками от IPlugin
    public class PluginClass : IPlugin
    {
        public string Id { get => "Plugin1"; }

        public void DoSmth(string txt)
        {
            Console.WriteLine($"{Id} - {txt}");
        }
    }

    public class Plugin2 : IPlugin
    {
        public string Id => "Plugin2";

        public void DoSmth(string txt)
        {
            Console.WriteLine($"{Id} - {txt}");
        }
    }


+ Результат работы
Plugin1 - plugin call
Plugin1 - plugin call
Plugin1 - plugin call
Plugin2 - plugin call
Plugin2 - plugin call
Plugin2 - plugin call
29 ноя 18, 11:06    [21748200]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Arm79
Member

Откуда: МО, Раменское
Сообщений: 3669
Забыл добавить - все 4 сборки в одном каталоге (bin хостового приложения)
29 ноя 18, 11:11    [21748210]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72766
Можете солюшен приложить?
29 ноя 18, 12:43    [21748423]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Arm79
Member

Откуда: МО, Раменское
Сообщений: 3669


К сообщению приложен файл (Plugins.7z - 11Kb) cкачать
29 ноя 18, 13:22    [21748482]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
fkthat
Member

Откуда:
Сообщений: 1163
Arm79,

Солюшен работает нормально. Попробуй выкосить все папки bin и по-новой собрать. Стопудово у тебя в bin лежит какая-то не та сборка.
29 ноя 18, 15:23    [21748724]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72766
Сборка та, я ее руками копирую из bin наружу.
29 ноя 18, 15:26    [21748732]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Arm79
Member

Откуда: МО, Раменское
Сообщений: 3669
fkthat,

у меня все хорошо ))) Это Antonariy мучается )




Antonariy, может у тебя платформа не та? разные версии фреймворков?
29 ноя 18, 15:39    [21748757]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72766
Arm79
fkthat,

у меня все хорошо ))) Это Antonariy мучается )




Antonariy, может у тебя платформа не та? разные версии фреймворков?
То есть я руками копирую бинарник, не работающий в одной папке, в другую папку, где он работает, а у него магическим образом в процессе копирования меняется версия фреймворка?
Уже обвиняли неуникальный ключ в пустом Dictionary, потом Linq, теперь эзотерику... Больше ада и оригинальных предположений! :))
29 ноя 18, 22:33    [21749184]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Arm79
Member

Откуда: МО, Раменское
Сообщений: 3669
Телепатов тут нет, информации недостаточно
29 ноя 18, 22:49    [21749199]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72766
Arm79
Телепатов тут нет, информации недостаточно
информации достаточно, чтобы исключать абсурдные причины.
29 ноя 18, 22:54    [21749202]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Antonariy
Arm79
Телепатов тут нет, информации недостаточно
информации достаточно, чтобы исключать абсурдные причины.

Проза жизни:
автор
Есть такой бородатый анекдот: Стоит новый русский около своего мерса, грустно так. Останавливается еще один: че, типа, стоишь? Да вот, сломалась — не едет. А стекла протирал? Протирал. А колеса пинал? Пинал. Ну тогда, братан, не знаю. anekdotov.net
30 ноя 18, 07:35    [21749330]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Antonariy
Больше ада и оригинальных предположений! :))
если у самого не получается, тебе нужно выключить мозги и делать все что предлагают. Как в больнице.
30 ноя 18, 07:50    [21749338]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Изопропил
Member

Откуда:
Сообщений: 31186
Antonariy
            var ass = Assembly.LoadFrom("Plugin.dll"); // текущая папка - bin
            var plug = ass.GetExportedTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).FirstOrDefault();

не работает
            var ass = Assembly.LoadFrom(Directory.GetCurrentDirectory() + "..\plugins\Plugin.dll");
            var plug = ass.GetExportedTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).FirstOrDefault();

работает

во втором случае - задан абсолютный путь

ass.CodeBase - корректный? (ass - это сильно)
https://stackoverflow.com/questions/1477843/difference-between-loadfile-and-loadfrom-with-net-assemblies
30 ноя 18, 09:27    [21749413]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72766
Изопропил
во втором случае - задан абсолютный путь
Без разницы, изначально в обоих случаях путь начинался с GetCurrentDirectory.

Изопропил
ass.CodeBase - корректный?
Проверю.

Изопропил
(ass - это сильно)
это ты еще на plug внимание не обратил)
30 ноя 18, 09:44    [21749435]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72766
Petro123
Antonariy
Больше ада и оригинальных предположений! :))
если у самого не получается, тебе нужно выключить мозги и делать все что предлагают. Как в больнице.
в этой больнице половина советчиков сами пациентами являются.
30 ноя 18, 09:45    [21749437]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Antonariy
в этой больнице половина советчиков сами пациентами являются.
ответ ты сам знаешь - тогда в платную клинику или в личку.
30 ноя 18, 09:56    [21749461]     Ответить | Цитировать Сообщить модератору
 Re: Reflection не отдупляет  [new]
fkthat
Member

Откуда:
Сообщений: 1163
Попробуй так:

var ass = Assembly.LoadFrom(Path.GetFullPath("Plugin.dll"));
30 ноя 18, 10:07    [21749489]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: 1 2      [все]
Все форумы / WinForms, .Net Framework Ответить