2012-03-08 46 views
5

时发生AssemblyResolve事件因此,我有一个WPF项目拉动了我的工作中另一个项目使用的dll。这是一堆依赖关系,我一直在使用这个技术:http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application将依赖关系嵌入到单个可执行文件中。Assembly.Load(byte())

现在,当我调用其中一个依赖关系的特定方法时,我点击了AssemblyResolve事件。我的OnResolveAssembly事件运行时,它发现程序集是嵌入式资源(cool!),并且“返回Assembly.Load(AsseyRawBytes)”。如果我在此时点击F11(在OnResolveAssembly开始时有一个断点),我会将另一个调用到同一个事件中。它也适用于相同的程序集(args.Name是相同的)。

如果我让这个运行我打了一个堆栈溢出,因为我永远不会逃避这个递归事件调用。

MSDN文档并没有真正地说Assembly.Load何时会失败,除了FileNotFoundException或BadImageFormatException。

我已经尝试解开OnResolveAssembly此刻我打电话Assembly.Load之前,但然后我的应用程序死亡神秘的死亡,即使在VS它只是去poof

我可能在这里违反了几条规则,但是从哪里开始寻找问题的一些想法是值得欢迎的。

我将开始在有问题的DLL中查看是否有关于它的错误的提示(也许它是混合程序集?)。

这里是我的OnResolveAssembly处理程序:

private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) 
{ 
    Assembly executingAssembly = Assembly.GetExecutingAssembly(); 
    AssemblyName assemblyName = new AssemblyName(args.Name); 

    string path = assemblyName.Name + ".dll"; 

    if (assemblyName.CultureInfo.Equals(System.Globalization.CultureInfo.InvariantCulture) == false) 
    { 
     path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path); 
    } 
    using (Stream stream = executingAssembly.GetManifestResourceStream(path)) 
    { 
     if (stream == null) 
      return null; 

     byte[] assemblyRawBytes = new byte[stream.Length]; 
     stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); 
     assemblyDictionary.Add(assemblyName.Name, Assembly.Load(assemblyRawBytes)); 
     return assemblyDictionary[assemblyName.Name]; 
    } 
} 

暂时,我已经通过我的所有资源进行迭代和他们试图Assembly.Load,并在字典存储它们进行检索(解决它在OnResolveAssembly活动期间):

[STAThread] 
public static void Main() 
{ 
    AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly; 
    Assembly executingAssembly = Assembly.GetExecutingAssembly(); 
    string[] resources = executingAssembly.GetManifestResourceNames(); 
    foreach (string resource in resources) 
    { 
     if (resource.EndsWith(".dll")) 
     { 
      using (Stream stream = executingAssembly.GetManifestResourceStream(resource)) 
      { 
       if (stream == null) 
        continue; 

       byte[] assemblyRawBytes = new byte[stream.Length]; 
       stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); 
       try 
       { 
        assemblyDictionary.Add(resource, Assembly.Load(assemblyRawBytes)); 
       } 
       catch (Exception ex) 
       { 
        System.Diagnostics.Debug.Print("Failed to load: " + resource + " Exception: " + ex.Message); 
       } 
      } 
     } 
    } 
    App.Main(); 
} 

private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) 
{ 
    Assembly executingAssembly = Assembly.GetExecutingAssembly(); 
    AssemblyName assemblyName = new AssemblyName(args.Name); 

    string path = assemblyName.Name + ".dll"; 

    if (assemblyDictionary.ContainsKey(path)) 
    { 
     return assemblyDictionary[path]; 
    } 
    return null; 
} 

现在似乎是工作的罚款(以下简称“失败”程序集将加载我的第二个片段罚款),但我很想了解为什么它不工作第一。

+2

需要代码片段。 – 2012-03-08 00:15:53

+0

添加了我的代码和我发现的解决方法。 – 2012-03-09 15:45:23

+0

@JonathanYee你是否真的从'Assembly.Load(byte [])'的调用中获得'AssemblyResolve'?这正是我正在寻找[这里](http://stackoverflow.com/questions/24718917/can-a-call-to-assembly-loadbyte-raise-the-appdomain-assemblyresolve-事件),但我无法构建这样一个例子。你能提供更多细节吗? – 2014-07-13 04:54:49

回答

3

从byte []加载程序集是一个很好的方式,最终在.dll地狱(你去的地方太多/复杂的依赖)。这里的问题是,虽然您将DLL加载到AppDomain,但它不会自动解析,当您需要它时再次为相关类型。 我对这个问题在这里说:AssemblyResolve Does not fire

长话短说,组件加载到不同的“上下文”的AppDomain内。 Load(byte [])使用的上下文不会自动解析Assemblies。

该解决方案跟踪加载的程序集并返回已加载的程序集,而不是第二次加载它。在我的回答中,有这样一个起点: Need to hookup AssemblyResolve event when DisallowApplicationBaseProbing = true

但我认为你的解决方法是正确的。

BTW。加载程序集两次是获得相同但不兼容类型的一种方法。曾经从MyAssembly将MyType的对象从同一个程序集转换为MyType,并得到空值?

这是一个温暖的“欢迎来到.dll地狱”。