【问题标题】:AppDomain.CurrentDomain.AssemblyResolve in dynamics crm动态 crm 中的 AppDomain.CurrentDomain.AssemblyResolve
【发布时间】:2013-07-10 09:29:11
【问题描述】:

所以,我看到很多文章提到使用 AppDomain.CurrentDomain.AssemblyResolve 在运行时将 DLL 从嵌入式资源加载到插件中(不使用 IlMerge)。但是,当我插入此代码时,在插件为我的主库抛出 TypeLoadException 消息之前,事件处理程序永远不会收到线程。

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

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

有人知道我需要做什么才能让它工作吗?

【问题讨论】:

    标签: c# plugins dynamics-crm-2011


    【解决方案1】:

    重要的是,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)
        {
            //...
        }
    }
    

    我还将外部程序集的几乎所有用法都移到了其他类中,这样我的插件类就根本不使用了。大多数情况下,这是出于谨慎考虑。

    【讨论】:

    • 好的...您的解决方案与我发布的解决方案没有太大区别...但是,您得到了复选标记,因为它让我想知道如果问题的复杂性逐渐降低,问题是否会持续存在增加。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-16
    • 2011-05-13
    • 1970-01-01
    相关资源
    最近更新 更多