插件场景如何实现程序集绑定重定向?
How to achieve assembly binding redirect in a plugin scenario?
我有一个我无法控制的 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,版本 =4.4.0.0,我订阅了 AppDomain.AssemblyResolve 以加载已部署的程序集。
当我在 GAC 中安装了两个 FSharp.Core 版本的机器上进行测试时,它们最终都加载了插件。
我的理解是绑定重定向将是这里的解决方案,但是如果不访问 app.config 怎么能做到呢?
您可以将 D 部署为 publisher policy 程序集。
这种方法的好处是客户端目录不需要包含 *.config 文件即可重定向到较新的版本。发布者策略允许程序集的发布者将 *.config 文件的二进制版本安装到 GAC(与程序集一起)。这样,CLR 将能够在 GAC 级别执行请求的重定向。
如果您想绕过某个应用的发布者政策,您可以在应用的 *.config 文件中使用 <publisherPolicy>
元素指定。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns=“urn:schemas-microsoft-com:asm.v1”>
<publisherPolicy apply="no" />
</assemblyBinding>
</runtime>
</configuration>
是的,的确如此。如果您正在编写插件,则 app.config 文件对于重定向程序集毫无用处。该插件将首先查找用户计算机上的 machine.config 文件,然后查找主程序的 *.config 文件.
下面是我在写SDL Trados 2017插件时,在插件场景下进行程序集绑定重定向的两步流程--
第一步:在插件本身中使用 try-catch 语句来发现有关加载失败的程序集的信息.
就我而言,我怀疑创建 Google Cloud AutoML 客户端所需的少数程序集之一是罪魁祸首,因此我在插件首次尝试创建 [=48] 的地方放置了一个 try-catch 语句=] Cloud AutoML 客户端:
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 客户端的过程中,该插件正在尝试 find.Google.Apis.Auth 版本 1.41.1.0。但是,为了让我的插件正确编译,我必须使用 NuGet 安装 Google.Apis.Auth 版本 1.42.0.0。因此需要程序集绑定重定向。
第二步:添加与该特定程序集相关的事件处理程序,这将在加载它之前更改其版本/public 密钥令牌信息。
在程序的最开始--初始化插件的主窗体window的地方,我添加了这段代码:
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.
从未接受过任何计算机科学或编程方面的正式培训,我不知道 robust/recommendable 这个解决方案如何,但它对我有用。
我有一个我无法控制的 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,版本 =4.4.0.0,我订阅了 AppDomain.AssemblyResolve 以加载已部署的程序集。
当我在 GAC 中安装了两个 FSharp.Core 版本的机器上进行测试时,它们最终都加载了插件。
我的理解是绑定重定向将是这里的解决方案,但是如果不访问 app.config 怎么能做到呢?
您可以将 D 部署为 publisher policy 程序集。
这种方法的好处是客户端目录不需要包含 *.config 文件即可重定向到较新的版本。发布者策略允许程序集的发布者将 *.config 文件的二进制版本安装到 GAC(与程序集一起)。这样,CLR 将能够在 GAC 级别执行请求的重定向。
如果您想绕过某个应用的发布者政策,您可以在应用的 *.config 文件中使用 <publisherPolicy>
元素指定。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns=“urn:schemas-microsoft-com:asm.v1”>
<publisherPolicy apply="no" />
</assemblyBinding>
</runtime>
</configuration>
是的,的确如此。如果您正在编写插件,则 app.config 文件对于重定向程序集毫无用处。该插件将首先查找用户计算机上的 machine.config 文件,然后查找主程序的 *.config 文件.
下面是我在写SDL Trados 2017插件时,在插件场景下进行程序集绑定重定向的两步流程--
第一步:在插件本身中使用 try-catch 语句来发现有关加载失败的程序集的信息.
就我而言,我怀疑创建 Google Cloud AutoML 客户端所需的少数程序集之一是罪魁祸首,因此我在插件首次尝试创建 [=48] 的地方放置了一个 try-catch 语句=] Cloud AutoML 客户端:
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 客户端的过程中,该插件正在尝试 find.Google.Apis.Auth 版本 1.41.1.0。但是,为了让我的插件正确编译,我必须使用 NuGet 安装 Google.Apis.Auth 版本 1.42.0.0。因此需要程序集绑定重定向。
第二步:添加与该特定程序集相关的事件处理程序,这将在加载它之前更改其版本/public 密钥令牌信息。 在程序的最开始--初始化插件的主窗体window的地方,我添加了这段代码:
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.
从未接受过任何计算机科学或编程方面的正式培训,我不知道 robust/recommendable 这个解决方案如何,但它对我有用。