在运行时交换强符号程序集

本文关键字:符号 程序集 交换 运行时 | 更新日期: 2023-09-27 18:19:25

我有一个引用第三方库的项目。库的制造商定期发布新版本。我的最终目标是能够在运行时选择在执行期间必须使用哪个版本。

目前,我正在尝试在运行时加载一个版本号高于编译期间使用的版本号的程序集。我编译了我的项目,用更新的版本替换了第三方库,并尝试运行应用程序。这就是我遇到问题的地方。我得到一个错误说:

"所定位的程序集的清单定义与程序集引用不匹配"

看到这个错误我并不感到惊讶,因为程序集是强符号的。我一直在寻找绕过这个问题的方法,但到目前为止没有任何运气。

我认为绑定重定向可以帮助我,但它的缺点是你不能指定一个"新版本"的范围。任何组合都可以工作,旧版本和新版本,反之亦然。

 <bindingRedirect oldVersion="1.2.7.0" newVersion="1.2.8.0" /> 
http://msdn.microsoft.com/en-us/library/eftw1fys.aspx

我还研究了动态调用,但是我失去了类型安全性(我的代码大量使用第三方程序集中定义的类型)。-->删除引用是困难的。

删除项目定义参考中的公钥也没有帮助。编译过程中使用的任何其他程序集版本都将失败。

<Reference Include="<assemblyname>">
  <SpecificVersion>False</SpecificVersion>
  <HintPath>..'..'Dependencies'<manufacturer>'1.2.7.0'<assemblyname>.dll</HintPath>
</Reference>

注意:在运行时加载和卸载程序集的逻辑已经存在。没有第三方库可用的接口

在运行时交换强符号程序集

您可以通过处理AppDomain上的AssemblyResolve事件来"修复"此问题(work around可能是更好的描述)。处理此事件使您的代码有机会提供在查找程序集的所有常规方法都无法找到匹配版本时需要加载的程序集。

在事件处理程序中,你需要检查ResolveEventArgs。名称属性查看该程序集是否是需要加载的程序集。Name属性将是正在加载的程序集的长名称。的小部件。. Net, Version=1.2.3.4, Culture=neutral, PublicKeyToken=xxxxxxxxxxx'。

一旦确定了正确的加载请求,只需加载程序集的正确版本(assembly。LoadFrom,组装。Load (Assembly.LoadWithPartialName),并从事件处理程序返回它。请注意大会。LoadWithPartialName被标记为过时,但如果目标程序集在GAC中,似乎是处理此问题的唯一方法。

// application initialization
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    if (args.Name.StartsWith("Widget.Net, Version="))
    {
        Assembly result = Assembly.LoadFrom("Widget.Net.dll");
        return result;
    }
    return null;
}
重要的是要意识到,虽然这"解决"了问题,但在任何意义上都不是一个好的解决方案。它完全颠覆了。net框架使用的程序集的正常版本和强名称检查。当你没有其他选择的时候,你会这样做,因为(就像在问题中一样)供应商把他们的程序集的版本控制搞砸了。您还依赖于它们在引用版本和加载版本之间对程序集中定义的类没有破坏性更改-即您使用的所有类,属性,方法等仍然存在并具有相同的签名。

为了维护至少一种伪装的安全性,至少在AssemblyResolve事件处理程序中检查以下内容将是一个非常好的主意:

  1. 加载的程序集版本比请求的版本新
  2. 加载和请求的程序集的公钥令牌匹配