Verholom
14-04-2014, 11:04
Задача такая: надо реализовать библиотеку, управляющую загрузкой и выгрузкой сборок. Причем выгрузка должна быть. То есть Assembly->LoadFrom не прокатит. хотя ранее вполне себе хватало такого подхода. Сейчас, по всей видимости, софтина будет расти постоянно - виды учета будут добавляться к ней как плагины. Плюс отчетность. то есть, в перспективе, всяко может быть. Надо обеспечить выгрузку плагинов при необходимости. Вариант с Assembly->LoadFrom эту проблему не решает, т. к. сборки остаются в главном домене. В нете куча примеров решения моего вопроса, но ни один не работает. Попервой пробовал загружать сборку через AppDomain::Load. Все прекрасно грузится, когда сборка лежит рядом с экзешником и грузится в главный домен, а не тот, из которого гружу ее. Когда сборка лежит где-то в другом месте, получаю ошибку, что, мол, не найдена она. Попробовал так:
this._app.DoCallBack(()=>System.Reflection.Assembly.LoadFrom(strFileName));
По логике, я внутри созданного мной домена (this._app) вызываю загрузку нужной сборки. Но получаю ошибку:
System.Runtime.Serialization.SerializationException: Тип "pluginlib.PluginManager+<>c__DisplayClass2" сборки "pluginlib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" не помечен как сериализуемый.
в System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
в pluginlib.PluginManager.LoadFile(String strFileName) в f:\1032\dev\pluginlib\pluginlib\PluginManager.cs:строка 83
pluginlib - это библиотека, которая будет управлять загрузкой и выгрузкой сборок. PluginManager - класс, который это делает. Но в объявлении класса стоит атрибут [Serializable]... Сперва подумал, что проблема в том, что сборка, которую загружаю, не содержит такой пометки класса. Ан нет... :help:
Вот полностью код конструктора класса, где создается домен:
public PluginManager(string strPath)
{
this._Path = strPath;
//чисто ради уникальности имени домена
string strDomainName = "Domain"+System.Math.Abs(System.DateTime.Now.ToBinary()).ToString();
AppDomainSetup appds=new AppDomainSetup();
appds.ApplicationBase=this._Path;
appds.ApplicationName = strDomainName;
this._app = AppDomain.CreateDomain(strDomainName, null, appds);
}
А вот - код загрузки сьборки по полному (с путем) имени файла:
public IEnumerable<IPlugin> LoadFile(string strFileName)
{
List<IPlugin> lstPluginTypes=new List<IPlugin>();
System.Type plgType = typeof(IPlugin);
System.Reflection.Assembly asm;
try
{
//в коментариях - варианты, испробованные ранее
//Сборка не найдена
//asm = this._app.Load(System.Reflection.AssemblyName.GetAssemblyName(strFileName));
//ошибка поиска класса
//pluginlib.IPlugin ip = (IPlugin)((this._app.CreateInstance(System.Reflection.AssemblyName.GetAssemblyName(strFileName).ToSt ring(), "testplugin")).Unwrap());
//this не помечен как сериализуемый
this._app.DoCallBack(()=>System.Reflection.Assembly.LoadFrom(strFileName));
}
catch(Exception e){
Console.WriteLine(e.ToString());
return null;
} :beta:
Тут тип возврата такой - каждая сборка может иметь несколько классов, реализующих нужный интерфейс.
IPlugin - простой инетрфейс с одним методом, который будет реализовывать каждая сборка
Затык пока только на загрузке файла сборки :closed-to
this._app.DoCallBack(()=>System.Reflection.Assembly.LoadFrom(strFileName));
По логике, я внутри созданного мной домена (this._app) вызываю загрузку нужной сборки. Но получаю ошибку:
System.Runtime.Serialization.SerializationException: Тип "pluginlib.PluginManager+<>c__DisplayClass2" сборки "pluginlib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" не помечен как сериализуемый.
в System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
в pluginlib.PluginManager.LoadFile(String strFileName) в f:\1032\dev\pluginlib\pluginlib\PluginManager.cs:строка 83
pluginlib - это библиотека, которая будет управлять загрузкой и выгрузкой сборок. PluginManager - класс, который это делает. Но в объявлении класса стоит атрибут [Serializable]... Сперва подумал, что проблема в том, что сборка, которую загружаю, не содержит такой пометки класса. Ан нет... :help:
Вот полностью код конструктора класса, где создается домен:
public PluginManager(string strPath)
{
this._Path = strPath;
//чисто ради уникальности имени домена
string strDomainName = "Domain"+System.Math.Abs(System.DateTime.Now.ToBinary()).ToString();
AppDomainSetup appds=new AppDomainSetup();
appds.ApplicationBase=this._Path;
appds.ApplicationName = strDomainName;
this._app = AppDomain.CreateDomain(strDomainName, null, appds);
}
А вот - код загрузки сьборки по полному (с путем) имени файла:
public IEnumerable<IPlugin> LoadFile(string strFileName)
{
List<IPlugin> lstPluginTypes=new List<IPlugin>();
System.Type plgType = typeof(IPlugin);
System.Reflection.Assembly asm;
try
{
//в коментариях - варианты, испробованные ранее
//Сборка не найдена
//asm = this._app.Load(System.Reflection.AssemblyName.GetAssemblyName(strFileName));
//ошибка поиска класса
//pluginlib.IPlugin ip = (IPlugin)((this._app.CreateInstance(System.Reflection.AssemblyName.GetAssemblyName(strFileName).ToSt ring(), "testplugin")).Unwrap());
//this не помечен как сериализуемый
this._app.DoCallBack(()=>System.Reflection.Assembly.LoadFrom(strFileName));
}
catch(Exception e){
Console.WriteLine(e.ToString());
return null;
} :beta:
Тут тип возврата такой - каждая сборка может иметь несколько классов, реализующих нужный интерфейс.
IPlugin - простой инетрфейс с одним методом, который будет реализовывать каждая сборка
Затык пока только на загрузке файла сборки :closed-to