private void AddPlugin(string FileName)
{
//Create a new assembly from the plugin file we're adding..
Assembly pluginAssembly = Assembly.LoadFrom(FileName);
//Next we'll loop through all the Types found in the assemblyforeach (Type pluginType in pluginAssembly.GetTypes())
{
if (pluginType.IsPublic) //Only look at public types
{
if (!pluginType.IsAbstract) //Only look at non-abstract types
{
//Gets a type object of the interface we need the plugins to match
Type typeInterface = pluginType.GetInterface("PluginInterface.IPlugin", true);
//Make sure the interface we want to use actually existsif (typeInterface != null)
{
//Create a new available plugin since the type implements the IPlugin interface
Types.AvailablePlugin newPlugin = new Types.AvailablePlugin();
//Set the filename where we found it
newPlugin.AssemblyPath = FileName;
//Create a new instance and store the instance in the collection for later use
//We could change this later on to not load an instance.. we have 2 options
//1- Make one instance, and use it whenever we need it.. it's always there
//2- Don't make an instance, and instead make an instance whenever we use it, then close it
//For now we'll just make an instance of all the plugins
newPlugin.Instance = (IPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
//Set the Plugin's host to this class which inherited IPluginHost
newPlugin.Instance.Host = this;
//Call the initialization sub of the plugin
newPlugin.Instance.Initialize();
//Add the new plugin to our collection herethis.colAvailablePlugins.Add(newPlugin);
//cleanup a bit
newPlugin = null;
}
typeInterface = null; //Mr. Clean
}
}
}
pluginAssembly = null; //more cleanup
}
Переделал все под свои нужды, но случайно забыл потереть старые плагины в папке plugins
Получил исключение на функции pluginAssembly.GetTypes() :
{"Не удается загрузить один или более запрошенных типов. Обратитесь к свойству LoaderExceptions для получения дополнительных сведений."}
А в LoaderExeptions :{"Не удалось загрузить тип \"PluginInterface.IPlugin\" из сборки \"PluginInterface, Version=1.0.3222.38063, Culture=neutral, PublicKeyToken=null\".":"PluginInterface.IPlugin"}
Подскажите как сделать так, чтобы правильно перечислить доступные типы в сборке Assembly ?
Здравствуйте, arkhivania, Вы писали:
A>Здравствуйте, Шалтай. A>Уверен что у вас просто стоит * в AssemblyInfo у сборок поэтому версия плывет.
В свойствах ваших сборок подключаемых к плагинам поставьте SpecificVersion=false
Здравствуйте, arkhivania, Вы писали:
A>Здравствуйте, Шалтай. A>Уверен что у вас просто стоит * в AssemblyInfo у сборок поэтому версия плывет.
Да, совершенно верно.
Но дело в том, что для одинаковых сборок загрузка работает и со *, но если я хочу закгузить плагин разработанный "сторонней организацией" не получится что ли?
Он же не будет согласовывать версию ..тем более что она и не важна для меня особо.
И я не понимаю тогда такой код:
Assembly pluginAssembly = Assembly.LoadFrom(FileName); // здесь по идее мы загружаем компоновочную информацию ИЗ САМОГО ПЛАГИНА (а не берем свою ... или я не так понял?)
// а дальше просто проходим по всем типам, объявленным в компоновочном файле
foreach (Type pluginType in pluginAssembly.GetTypes())
Но GetTypes по прежнему валится, если я загружаю разные сборки ... как это победить?
Здравствуйте, OrSol, Вы писали:
OS>Здравствуйте, arkhivania, Вы писали:
A>>Здравствуйте, Шалтай. A>>Уверен что у вас просто стоит * в AssemblyInfo у сборок поэтому версия плывет. OS>В свойствах ваших сборок подключаемых к плагинам поставьте SpecificVersion=false
Я нашел SpecificVersion в поле Reference при создании проекта на этапе компиляции (запихать туда dll и поставить SpecificVersion), но на этапе компиляции я не знаю какой плагин вздумает оказаться в папке Plugins и с какой версией ...
Как сделать SpecificVersion=false динамически я не нашел, подскажите если можно ...
Ш>private void AddPlugin(string FileName)
Ш>{
Ш> //Create a new assembly from the plugin file we're adding..
Ш> Assembly pluginAssembly = Assembly.LoadFrom(FileName);
Ш> //Next we'll loop through all the Types found in the assembly
Ш> foreach (Type pluginType in pluginAssembly.GetTypes())
Ш> {
Ш> //....код
Ш> }
Ш>}
Ш>
Ш>Переделал все под свои нужды, но случайно забыл потереть старые плагины в папке plugins Ш>Получил исключение на функции pluginAssembly.GetTypes() : Ш>{"Не удается загрузить один или более запрошенных типов. Обратитесь к свойству LoaderExceptions для получения дополнительных сведений."} Ш>А в LoaderExeptions :{"Не удалось загрузить тип \"PluginInterface.IPlugin\" из сборки \"PluginInterface, Version=1.0.3222.38063, Culture=neutral, PublicKeyToken=null\".":"PluginInterface.IPlugin"}
Ш>Подскажите как сделать так, чтобы правильно перечислить доступные типы в сборке Assembly ?
А ловить этот самый эксепшн ?
try
{
// Грузим сборку
}
catch
{
// Вай, не вышло, пишем в лог ошибку
}
Всё заканчивается плохо. Если что-то закончилось хорошо — значит оно еще не закончилось.
Здравствуйте, Unforgiver, Вы писали:
Ш>>Подскажите как сделать так, чтобы правильно перечислить доступные типы в сборке Assembly ?
U>А ловить этот самый эксепшн ?
U>
U>try
U>{
U>// Грузим сборку
U>}
U>catch
U>{
U>// Вай, не вышло, пишем в лог ошибку
U>}
U>
Да, ловить ошибку не проблема.
Проблема в том, чтобы грузить библиотеки-плагины разных версий. И чтобы их можно было вызывать из главной программы.
Сейчас, если я делаю Assembly.Load — получаю сборку DLL, а затем GetType — чтобы посмотреть что у нее внутри — ошибка, но ТИПЫ ВНУТРИ ТОЧНО ЕСТЬ,
т.к. я просто скопировал библиотеку-плагин другого проекта (примера с которого я делал) и там все работало.
Получается, что механизмы одинаковые, но что-то не сходится, не пойму почему так т.к. пока плохо разбираюсь во всем этом.
Есть вариант использовать неуправляемый код и загружать win32 библиотеки как LoadLibrary + GetProcAdress ...
Но разве это правильно? Подскажите пожалуйста едиственный ли это выход и больше никак не победить версии? Зачем они вообще нужны тогда?
Здравствуйте, Шалтай, Вы писали:
Ш>Переделал все под свои нужды, но случайно забыл потереть старые плагины в папке plugins Ш>Получил исключение на функции pluginAssembly.GetTypes() : Ш>{"Не удается загрузить один или более запрошенных типов. Обратитесь к свойству LoaderExceptions для получения дополнительных сведений."} Ш>А в LoaderExeptions :{"Не удалось загрузить тип \"PluginInterface.IPlugin\" из сборки \"PluginInterface, Version=1.0.3222.38063, Culture=neutral, PublicKeyToken=null\".":"PluginInterface.IPlugin"}
Ш>Подскажите как сделать так, чтобы правильно перечислить доступные типы в сборке Assembly ?
А какой смысл смотреть типы, если этот плагин писался под старую версию программы? Может он уже не будет работать? Если уж очень сильно хочеться загружать плагины, которые писались под старые версии, то надо прописать в конфигурационном файле:
Здравствуйте, Шалтай, Вы писали:
Ш>Здравствуйте, Unforgiver, Вы писали:
Ш>>>Подскажите как сделать так, чтобы правильно перечислить доступные типы в сборке Assembly ?
U>>А ловить этот самый эксепшн ?
U>>
U>>try
U>>{
U>>// Грузим сборку
U>>}
U>>catch
U>>{
U>>// Вай, не вышло, пишем в лог ошибку
U>>}
U>>
Ш>Да, ловить ошибку не проблема. Ш>Проблема в том, чтобы грузить библиотеки-плагины разных версий. И чтобы их можно было вызывать из главной программы. Ш>Сейчас, если я делаю Assembly.Load — получаю сборку DLL, а затем GetType — чтобы посмотреть что у нее внутри — ошибка, но ТИПЫ ВНУТРИ ТОЧНО ЕСТЬ, Ш>т.к. я просто скопировал библиотеку-плагин другого проекта (примера с которого я делал) и там все работало. Ш>Получается, что механизмы одинаковые, но что-то не сходится, не пойму почему так т.к. пока плохо разбираюсь во всем этом.
Ш>Есть вариант использовать неуправляемый код и загружать win32 библиотеки как LoadLibrary + GetProcAdress ... Ш>Но разве это правильно? Подскажите пожалуйста едиственный ли это выход и больше никак не победить версии? Зачем они вообще нужны тогда?
При чем тут версии ? ИМХО, тут дело в другом.
Например:
Был у тебя интерфейс "А" с методом "a" и параметром типа string.
Сборки-плагины содержат типы, наследующие этот интерфейс.
В каждом типе был метод
public void a(string b)
{
}
Затем, ты поменял тип входного параметра на int.
И написал новый плагин, у которого есть метод
public void a(int c)
{
}
Первый плагин уже не подтянется, и будет давать тебе ту самую ошибку при вызове Assembly.GetTypes().
Как ты хочешь работать со старыми плагинами после изменение интерфейса для них?
Всё заканчивается плохо. Если что-то закончилось хорошо — значит оно еще не закончилось.
U>При чем тут версии ? ИМХО, тут дело в другом.
U>Например: U>Был у тебя интерфейс "А" с методом "a" и параметром типа string. U>Сборки-плагины содержат типы, наследующие этот интерфейс. U>В каждом типе был метод
U>
U>public void a(string b)
U>{
U>}
U>
U>Затем, ты поменял тип входного параметра на int. U>И написал новый плагин, у которого есть метод U>
U>public void a(int c)
U>{
U>}
U>
U>Первый плагин уже не подтянется, и будет давать тебе ту самую ошибку при вызове Assembly.GetTypes().
!!!! А почему плагин выдает ошибку при перечислении, а не при том же поиске интерфейса внутри pluginType.GetInterface("PluginInterface.IPlugin", true) ?
U>Как ты хочешь работать со старыми плагинами после изменение интерфейса для них?
Да, это я понимаю. Может я не правильно объяснил. Дело в том, что:
Есть программа (версии могут ее менятся), есть DLL-там хранятся интерфейсы плагинов и хостов, и есть DLL в виде самих плагинов.
Так вот, я хочу чтобы было так : Программа обновляется разработчиком (версии 1.2.3 и т.п.)
Обновляются плагины сторонними разработчиками версии разные), но чтобы пока не обновился сам интерфейс они работали друг с другом, не зависимо от версии их самих.
Здравствуйте, V.Petrovski, Вы писали:
VP>Здравствуйте, Шалтай, Вы писали:
Ш>>Переделал все под свои нужды, но случайно забыл потереть старые плагины в папке plugins Ш>>Получил исключение на функции pluginAssembly.GetTypes() : Ш>>{"Не удается загрузить один или более запрошенных типов. Обратитесь к свойству LoaderExceptions для получения дополнительных сведений."} Ш>>А в LoaderExeptions :{"Не удалось загрузить тип \"PluginInterface.IPlugin\" из сборки \"PluginInterface, Version=1.0.3222.38063, Culture=neutral, PublicKeyToken=null\".":"PluginInterface.IPlugin"}
Ш>>Подскажите как сделать так, чтобы правильно перечислить доступные типы в сборке Assembly ?
VP>А какой смысл смотреть типы, если этот плагин писался под старую версию программы? Может он уже не будет работать? Если уж очень сильно хочеться загружать плагины, которые писались под старые версии, то надо прописать в конфигурационном файле: VP>
Пока не поменялся интерфейс — они будут друг с другом работать, внутри же может алгоритмы менятся и это влияет на версии плагинов, но на интерфейс общения это же не влияет.
Я все перерыл не могу понять куда вписать тот код, что вы привели ... подскажите пожалуйста
Здравствуйте, Шалтай, Вы писали:
Ш>Пока не поменялся интерфейс — они будут друг с другом работать, внутри же может алгоритмы менятся и это влияет на версии плагинов, но на интерфейс общения это же не влияет. Ш>Я все перерыл не могу понять куда вписать тот код, что вы привели ... подскажите пожалуйста
В sturtup проект добавить App.Config через "Add|New Item...|Application Configuration File". Текст вставлять не один в один, чтобы всё заработало, вам надо будет подписать сборку PluginInterface (чтобы publicKeyToken небыл равен null). Для этого в свойствах проекта есть закладка Singing. И обязательно проверте, чтобы publicKeyToken и newVersion были правильными.
Здравствуйте, Шалтай, Вы писали:
U>>Первый плагин уже не подтянется, и будет давать тебе ту самую ошибку при вызове Assembly.GetTypes().
Ш>!!!! А почему плагин выдает ошибку при перечислении, а не при том же поиске интерфейса внутри pluginType.GetInterface("PluginInterface.IPlugin", true) ?
Ну мне думается так (надо почитать конечно, я не вникал в подробности):
Есть сборка. Ты ее грузишь, вызываешь метод GetTypes().
Наверняка этот метод не просто тупо перебирает типы. А еще проверяет, чтоб они были валидные.
U>>Как ты хочешь работать со старыми плагинами после изменение интерфейса для них?
Ш>Да, это я понимаю. Может я не правильно объяснил. Дело в том, что: Ш>Есть программа (версии могут ее менятся), есть DLL-там хранятся интерфейсы плагинов и хостов, и есть DLL в виде самих плагинов. Ш>Так вот, я хочу чтобы было так : Программа обновляется разработчиком (версии 1.2.3 и т.п.)
Пусть обновляется. Если в ней интерфейсы для плагинов не трогать — какие проблемы тогда ?
Я так и делал. Менял основной функционал, а плагины жили сами по себе, до тех пор пока не менялись интерфейсы для них. Тогда старые плагины переставали грузиться и надо было их переписывать. К циферкам в версии я не привязывался.
Ш>Обновляются плагины сторонними разработчиками версии разные), но чтобы пока не обновился сам интерфейс они работали друг с другом, не зависимо от версии их самих.
Ты хочешь сказать, что была у тебя программа 1.0.0.0 и плагин 1.0.0.0, после этого ты просто поменял в AssemblyInfo основной программы версию на 1.0.0.1 (не затрагивал интерфейсов для плагина и типов, которые он использует), и плагин перестал грузиться ?
Всё заканчивается плохо. Если что-то закончилось хорошо — значит оно еще не закончилось.
Здравствуйте, Unforgiver, Вы писали:
U>Здравствуйте, Шалтай, Вы писали:
U>>>Первый плагин уже не подтянется, и будет давать тебе ту самую ошибку при вызове Assembly.GetTypes().
Ш>>!!!! А почему плагин выдает ошибку при перечислении, а не при том же поиске интерфейса внутри pluginType.GetInterface("PluginInterface.IPlugin", true) ?
U>Ну мне думается так (надо почитать конечно, я не вникал в подробности):
U>Есть сборка. Ты ее грузишь, вызываешь метод GetTypes(). U>Наверняка этот метод не просто тупо перебирает типы. А еще проверяет, чтоб они были валидные.
U>>>Как ты хочешь работать со старыми плагинами после изменение интерфейса для них?
Ш>>Да, это я понимаю. Может я не правильно объяснил. Дело в том, что: Ш>>Есть программа (версии могут ее менятся), есть DLL-там хранятся интерфейсы плагинов и хостов, и есть DLL в виде самих плагинов. Ш>>Так вот, я хочу чтобы было так : Программа обновляется разработчиком (версии 1.2.3 и т.п.) U>Пусть обновляется. Если в ней интерфейсы для плагинов не трогать — какие проблемы тогда ? U>Я так и делал. Менял основной функционал, а плагины жили сами по себе, до тех пор пока не менялись интерфейсы для них. Тогда старые плагины переставали грузиться и надо было их переписывать. К циферкам в версии я не привязывался.
Ш>>Обновляются плагины сторонними разработчиками версии разные), но чтобы пока не обновился сам интерфейс они работали друг с другом, не зависимо от версии их самих. U>Ты хочешь сказать, что была у тебя программа 1.0.0.0 и плагин 1.0.0.0, после этого ты просто поменял в AssemblyInfo основной программы версию на 1.0.0.1 (не затрагивал интерфейсов для плагина и типов, которые он использует), и плагин перестал грузиться ?
Спасибо большое за ответы всем участникам, кое как стал разбираться в вопросе.
Прочитал статьи по этому вопросу на rsdn.ru, понял что к чему.
Помимо того, что я не понимал что такое сборки, я еще и был невнимателен к тому, как собирал плагины. Они у меня линковались с интерфейсом, а сам DLL файл интерфейса не обновлялся при правках, в проекте. А я думал, что он обновляется автоматически.
Теперь все в порядке, можно двигаться дальше ))))) Ура!
Здравствуйте, V.Petrovski, Вы писали:
VP>Здравствуйте, Шалтай, Вы писали:
Ш>>Пока не поменялся интерфейс — они будут друг с другом работать, внутри же может алгоритмы менятся и это влияет на версии плагинов, но на интерфейс общения это же не влияет. Ш>>Я все перерыл не могу понять куда вписать тот код, что вы привели ... подскажите пожалуйста
VP>В sturtup проект добавить App.Config через "Add|New Item...|Application Configuration File". Текст вставлять не один в один, чтобы всё заработало, вам надо будет подписать сборку PluginInterface (чтобы publicKeyToken небыл равен null). Для этого в свойствах проекта есть закладка Singing. И обязательно проверте, чтобы publicKeyToken и newVersion были правильными.