动态crm中的AppDomain.CurrentDomain.AssemblyResolve

本文关键字:CurrentDomain AssemblyResolve AppDomain 中的 crm 动态 | 更新日期: 2023-09-27 18:21:59

因此,我看到许多文章提到使用AppDomain.CurrentDomain.AssemblyResolve在运行时将嵌入资源中的DLL加载到插件中(不使用IlMerge)。然而,当我插入此代码时,在插件为我的主库抛出TypeLoadException消息之前,事件处理程序从未接收到线程。

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

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

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

动态crm中的AppDomain.CurrentDomain.AssemblyResolve

在引用计划通过回调加载的程序集中的任何类型之前,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)
    {
        //...
    }
}

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