2013-07-11 158 views
5

所以,我已经有很多文章参考使用AppDomain.CurrentDomain.AssemblyResolve从运行时(不使用IlMerge)将嵌入式资源中的DLL加载到插件中。但是,当我插入此代码时,事件处理程序在插件为我的主库引发TypeLoadException消息之前从不接收线程。AppDomain.CurrentDomain.AssemblyResolve in dynamics crm

我已经尝试将代码放在静态构造函数中,在Execute方法内部和主构造函数中;虽然事件处理程序已注册,但处理程序中的断点不会被触发。

该环境是Dynamics CRM 2011的最新汇总和使用SDK开发工具插件项目和插件类生成。

任何人都知道我需要做些什么才能使其工作?

回答

4

AssemblyResolve事件注册发生在从计划通过该回调加载的程序集中引用任何类型之前发生很重要。即使不在静态构造函数中引用类型,也必须确保在类外部程序集中引用类型的类或其基类中没有静态变量。

这里是我如何做到这一点: 我有一个单独的类来处理组件加载,恰当地命名为AssemblyLoader:

using System; 
using System.IO; 
using System.Linq; 
using System.Reflection; 

internal static class AssemblyLoader 
{ 
    internal static void RegisterAssemblyLoader() 
    { 
     AppDomain currentDomain = AppDomain.CurrentDomain; 
     currentDomain.AssemblyResolve -= OnResolveAssembly; 
     currentDomain.AssemblyResolve += OnResolveAssembly; 
    } 

    private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args) 
    { 
     return LoadAssemblyFromManifest(args.Name); 
    } 

    private static Assembly LoadAssemblyFromManifest(string targetAssemblyName) 
    { 
     Assembly executingAssembly = Assembly.GetExecutingAssembly(); 
     AssemblyName assemblyName = new AssemblyName(targetAssemblyName); 

     string resourceName = DetermineEmbeddedResourceName(assemblyName, executingAssembly); 

     using (Stream stream = executingAssembly.GetManifestResourceStream(resourceName)) 
     { 
      if (stream == null) 
       return null; 

      byte[] assemblyRawBytes = new byte[stream.Length]; 
      stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length); 


      return Assembly.Load(assemblyRawBytes); 
     } 

    } 

    private static string DetermineEmbeddedResourceName(AssemblyName assemblyName, Assembly executingAssembly) 
    { 
     //This assumes you have the assemblies in a folder named "EmbeddedAssemblies" 
     string resourceName = string.Format("{0}.EmbeddedAssemblies.{1}.dll", 
              executingAssembly.GetName().Name, assemblyName.Name); 

     //This logic finds the assembly manifest name even if it's not an case match for the requested assembly       
     var matchingResource = executingAssembly.GetManifestResourceNames() 
               .FirstOrDefault(res => res.ToLower() == resourceName.ToLower()); 

     if (matchingResource != null) 
     { 
      resourceName = matchingResource; 
     } 
     return resourceName; 
    } 
} 

然后,在我的插件类,我使用静态构造函数调用到我的AssemblyLoader 。通过将逻辑移动到单独的类中,我限制了我在插件类的静态上下文中引用的类型的数量,从而降低了我意外引用外部程序集中的某些内容的风险。

using System; 
using Microsoft.Xrm.Sdk; 

public class MyPlugin : IPlugin 
{ 
    static MyPlugin() 
    { 
     AssemblyLoader.RegisterAssemblyLoader(); 
    } 

    public void Execute(IServiceProvider serviceProvider) 
    { 
     //... 
    } 
} 

我还将外部程序集的所有用法移到其他类中,以便我的插件类完全不使用它。大多数情况下,这是非常谨慎的。

+0

ok ......您的解决方案与我发布的内容没有实质性差异......但是,您会得到复选标记,因为它让我想知道如果问题的复杂性降低并逐渐增加,问题是否会持续存在。 –

+0

相同的技术是否可以与自定义工作流配合使用? –