【问题标题】:Swap strongly signed assembly at runtime在运行时交换强签名程序集
【发布时间】:2012-01-31 21:22:14
【问题描述】:

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

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

“找到的程序集的清单定义与程序集引用不匹配”

看到这个错误我并不意外,因为程序集是强签名的。我寻找绕过这个的方法,但到目前为止没有任何运气。

我认为绑定重定向可以帮助我,但它的缺点是您无法指定“新版本”的范围。任何组合都应该有效,旧版本和新版本,反之亦然。

 <bindingRedirect oldVersion="1.2.7.0" newVersion="1.2.8.0" /> 

http://msdn.microsoft.com/en-us/library/eftw1fys.aspx

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

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

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

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

【问题讨论】:

  • Brr,这是要求 DLL Hell 作为一项功能。它与强命名没有任何关系,由于 [AssemblyVersion] 不匹配而引发异常。 bindingRedirect 确实是唯一好的解决方案。除非你能说服供应商只为兼容的程序集增加 [AssemblyFileVersion],否则你会陷入困境。否则,递增 [AssemblyVersion] 意味着“不兼容,甚至不要尝试”。
  • @HansPassant AssemblyVersion 确实增加了,导致清单不匹配。说清单不匹配只会发生在强签名的程序集中是否正确?还是该问题也适用于未签名的程序集? Assembly Versioning
  • 不,这里只有 [AssemblyVersion] 重要。它会以完全相同的方式在未签名的程序集中失败。

标签: c# plugins dll assemblies


【解决方案1】:

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

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

一旦识别出正确的加载请求,只需加载正确版本的程序集(Assembly.LoadFrom、Assembly.Load、Assembly.LoadWithPartialName)并从事件处理程序中返回。请注意,Assembly.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. 已加载和请求的程序集的公钥令牌匹配

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多