c# - 动态 crm 中的 AppDomain.CurrentDomain.AssemblyResolve

标签 c# plugins dynamics-crm-2011

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

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

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

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

最佳答案

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

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

关于c# - 动态 crm 中的 AppDomain.CurrentDomain.AssemblyResolve,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17604734/

相关文章:

c# - 在 LINQ to SQL 中处理 DataContext 的最佳方式

javascript - 如何嵌入 Google Plus 撰写评论

当 lambda 表达式没有时,Linq to CRM(早期绑定(bind))join 语句会引发异常

dynamics-crm-2011 - 如何连接到 CRM Dynamics Online Odata 端点 LinqPad?

c# - 为什么编译器抛出错误 CS0165 : Use of unassigned local variable?

c# - 盗取系统dll代码行为并重新实现是否违法?

c# - 如何增加 ASP .NET Core 3.0 应用程序中的最大线程数

java - Eclipse如何重构变量名?

Maven:无法解析的构建扩展

sql - 两个实体如何与 1 :N relationship related?