У меня есть приложение a.exe
, которое работает нормально и загрузило сборку b.dll
, которая является модулем Prism, если это имеет значение.Эта dll загружается из каталога, который не находится в пути, но находится в каталоге, в котором находится a.exe
.
Загрузка сборки выполняется Prism и настроена следующим образом:
public class MyModuleCatalog : ComposablePartCatalog
{
private readonly AggregateCatalog _catalog;
public MyModuleCatalog()
{
//directory Modules is not in the path, but all
//dependencies of b.dll are, so b.dll gets loaded fine
var asmCat = new AssemblyCatalog( "Modules/b.dll" );
_catalog.Catalogs.Add( asmCat );
}
public override IQueryable<ComposablePartDefinition> Parts
{
get { return _catalog.Parts; }
}
}
class BootStrapper : MefBootstrapper
{
....
protected override void ConfigureAggregateCatalog()
{
base.ConfigureAggregateCatalog();
AggregateCatalog.Catalogs.Add( new AssemblyCatalog( Assembly.GetExecutingAssembly() ) );
AggregateCatalog.Catalogs.Add( new MyModuleCatalog() );
}
....
}
В b.dll
есть класс ImInB
:
[Export]
public class ImInB
{
public void DoIt()
{
try
{
var stream = new MemoryStream();
//using System.Runtime.Serialization.Formatters.
var formatter = new BinaryBinaryFormatter();
//serialize our type
formatter.Serialize( stream, this.GetType() );
//get it back
stream.Position = 0;
var obj = formatter.Deserialize( stream ); //this throws??
}
catch( Exception e )
{
}
}
}
Это всего лишь пример кода и является частью существующей инфраструктуры, которая загружает / сохраняет настройки в базе данных.Тип объекта всегда сериализуется и служит ключом к базе данных.После десериализации тип возвращается обратно как двойная проверка на объект, который загружается.Функция вызывается из a.exe
:
container.GetExportedValue<ImInB>().DoIt();
Исключение, которое выдается при десериализации типа (который был успешно сериализован двумя строками ранее):
"Could not load file or assembly 'b.dll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
or one of its dependencies. The system cannot find the file specified."
Вопросы:
- Как это вообще возможно?Функция вызывается из dll, но говорит, что не может найти dll.
- Как мне это исправить?Как мне сказать
Deserialize
эй, что dll уже загружена, не ищите ее
ОБНОВЛЕНИЕ мой второй вопрос в основном ответилФеликс К;следующий код решает проблему:
public static class AssemblyResolverFix
{
//Looks up the assembly in the set of currently loaded assemblies,
//and returns it if the name matches. Else returns null.
public static Assembly HandleAssemblyResolve( object sender, ResolveEventArgs args )
{
foreach( var ass in AppDomain.CurrentDomain.GetAssemblies() )
if( ass.FullName == args.Name )
return ass;
return null;
}
}
//in main
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolverFix.HandleAssemblyResolve;
Это также доказывает, что сборка эффективно загружена, включая все ее зависимости, поэтому остается первый вопрос: для меня загадка, почему фреймворк не может понять этосамо собой.Более того, я не могу воспроизвести его во втором приложении, которое использует примерно ту же структуру.