在运行时交换强签名程序集

时间:2012-01-02 14:36:37

标签: c# plugins dll assemblies

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

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

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

不匹配

我没有被要求看到这个错误,因为程序集是强烈签名的。我想办法绕过这个,但到目前为止没有运气。

我认为Binding Redirection可以帮助我,但它的缺点是你不能指定一系列的“newversions”。任何组合都应该有效,对于较新的版本较旧,反之亦然。

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

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

我也看了动态调用,但后来我放松了类型安全(我的代码广泛使用了第3方程序集中定义的类型)。 - &GT;删除引用很困难。

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

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

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

1 个答案:

答案 0 :(得分: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. 已加载和请求的程序集的公钥标记匹配