如何在插件场景中实现程序集绑定重定向?

时间:2017-08-04 15:13:09

标签: .net plugins f# assembly-resolution assembly-binding-redirect

我有一个plugin P延伸和application A(.NET40)我无法控制。
P程序集(.NET40)有一个shared dependency D(.NET35)。

P和D都依赖于FSharp.Core,但版本不同:

P针对FSharp.Core, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a编译 D是针对FSharp.Core, Version=2.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

编译的

仅部署了FSharp.Core,Version = 4.4.0.0,我订阅AppDomain.AssemblyResolve以加载已部署的程序集。

当我在我的机器上测试,其中两个FSharp.Core版本都安装在GAC中时,它们最终都被加载了插件。

我的理解是绑定重定向是这里的解决方案但是如何在不访问app.config的情况下完成?

2 个答案:

答案 0 :(得分:2)

您可以将D部署为publisher policy程序集。

此方法的好处是客户端目录不需要包含* .config文件来重定向到更新的版本。发布者策略允许程序集的发布者将* .config文件的二进制版本安装到GAC(以及程序集)。这样,CLR就能够在GAC级别执行请求的重定向。

如果您想绕过某个应用的发布商政策,可以使用<publisherPolicy>元素在应用的* .config文件中指定。

<?xml version="1.0" encoding="utf-8" ?>
<configuration> 
    <runtime>
        <assemblyBinding xmlns=“urn:schemas-microsoft-com:asm.v1”> 
            <publisherPolicy apply="no" />
        </assemblyBinding>
    </runtime> 
</configuration>

答案 1 :(得分:2)

是的,的确如此。如果您正在编写插件,则app.config文件对于重定向程序集是无用的。该插件将首先在用户计算机上的 machine.config 文件中查找,然后在主程序的 *。config 文件中查找。

这是在为SDL Trados 2017编写插件时在插件方案中执行程序集绑定重定向的两步过程-

第一步:在插件本身中使用try-catch语句来查找有关无法加载的程序集的信息
就我而言,我怀疑创建Google Cloud AutoML客户端所需的少数程序集之一应该归咎于我,因此我在插件首次尝试创建Google Cloud AutoML客户端的位置附近放置了try-catch语句: >

    try
    {
        client = AutoMlClient.Create(); 
    }
    catch (Exception err)
    {
        using (System.IO.StreamWriter file = new System.IO.StreamWriter("C:/Desktop/log.txt", true))
        {
            file.WriteLine(err.ToString());
        }
    }

当我检查在错误期间创建的“ log.txt”文件时,发现以下信息:

    System.IO.FileNotFoundException: Could not load file or assembly 'Google.Apis.Auth, Version=1.41.1.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab' or one of its dependencies. The system cannot find the file specified.

所以!很明显,在创建AutoML客户端的过程中,该插件正在尝试查找1.4.1.0.1.0版的Google.Apis.Auth。但是,为了使我的插件正确编译,我必须使用NuGet安装Google.Apis.Auth版本1.42.0.0。因此,需要对程序集绑定进行重定向。

第二步:添加与该特定程序集相关的事件处理程序,该事件处理程序将在加载之前更改其版本/公钥令牌信息。 在程序的最开始-初始化插件的主窗体窗口的地方,我添加了以下代码:

    public Main_form()
    {
        InitializeComponent();

        Version V14200 = new Version("1.42.0.0");
        RedirectAssembly("Google.Apis.Auth", V14200, "4b01fa6e34db77ab");
    }

    public static void RedirectAssembly(string assembly_name, Version targetVersion, string publicKeyToken)
    {
        ResolveEventHandler handler = null;

        handler = (sender, args) => {
            //gets the name of the assembly being requested by the plugin
            var requestedAssembly = new AssemblyName(args.Name);

            //if it is not the assembly we are trying to redirect, return null
            if (requestedAssembly.Name != assembly_name)
                return null;

            //if it IS the assembly we are trying to redirect, change it's version and public key token information
            requestedAssembly.Version = targetVersion;
            requestedAssembly.SetPublicKeyToken(new AssemblyName("x, PublicKeyToken=" + publicKeyToken).GetPublicKeyToken());
            requestedAssembly.CultureInfo = CultureInfo.InvariantCulture;

            //finally, load the assembly
            return Assembly.Load(requestedAssembly);
        };
        AppDomain.CurrentDomain.AssemblyResolve += handler;
    }

因此,基本上,您必须从插件(使用try-catch语句)获取有关哪个程序集无法加载的信息。然后,您必须添加一个事件处理程序,该事件处理程序将在有问题的程序集开始加载时生效。

就我而言,我知道问题出在Google.Apis.Auth上-该插件想加载1.41.1.0版,但我的插件包含1.42.0.0版。当插件开始寻找Google.Apis.Auth(1.41.1.0)时,事件处理程序将介入并更改版本号,因此插件将加载1.42.0.0版。

我从未接受过任何计算机科学或编程方面的正规培训,所以我不知道该解决方案的强大/推荐性,但是它对我有用。