我有一个运行正常的应用程序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已经加载了,不去寻找它
UPDATE
我的第二个问题基本上由Felix K回答;以下代码修复了该问题:
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;
这也证明了程序集是有效加载的,包括它的所有依赖项,所以第一个问题仍然存在:对我来说,为什么框架本身无法解决这个问题,这是一种谜.此外,我无法在使用大致相同结构的第二个应用程序中重现它.
解决方法
我不知道为什么在dll已经加载时会发生这种情况,但我认为这与序列化本身无关,对我来说它看起来像是一个.NET错误.
这可能会帮助你,或指出你正确的方向:
AppDomain current = AppDomain.CurrentDomain; current.AssemblyResolve += new ResolveEventHandler(HandleAssemblyResolve); static Assembly HandleAssemblyResolve(object sender,ResolveEventArgs args) { /* Load the assembly specified in 'args' here and return it,if the assembly is already loaded you can return it here */ }
每当缺少一个DLL时,都会调用resolve方法,因此当你的dll丢失时也会发生这种情况. dotNET无法找到它,因为它位于“Modules”文件夹中,因此您必须自己解析引用.