【问题标题】:How to let CLR know which assembly to pick from GAC?如何让 CLR 知道从 GAC 中选择哪个程序集?
【发布时间】:2012-09-25 17:19:16
【问题描述】:
using System;
using System.Collections.Generic;
using System.Text;
using Shapes;

namespace ShapeUser
{
    public class ShapeUser
    {
        public static void Main() 
        {
            Circle c = new Circle(1.0F);
            Console.WriteLine("Area of Circle(1.0) is {0}", c.Area());
            Console.ReadKey(); // press a key to exit program
        }
    }
}

此程序正在使用 GAC 中的 Shapes 程序集。如果只有一个程序集,那很好。但是,GAC 可能包含其他名称相同(但版本和密钥不同)的程序集。

那么,如何告诉 CLR 只加载我的程序集而不是其他同名的程序集?

我很困惑。我知道它受到公钥加密的保护,但我们仍然应该在我们访问它的程序中拥有一些私钥。请解开我的困惑。

【问题讨论】:

  • 当您在项目中引用 Shapes 时,您可以指定使用特定版本。如果该特定版本不可用,您的程序将无法加载。
  • @托雷斯!假设我已经在其他地方部署了我的软件。现在我只是更新程序集版本(以增强它),我永远不希望我的应用程序是特定于版本的。我想如果我们提到“1.0.*”,它需要最新版本。

标签: c# .net gac .net-assembly


【解决方案1】:

当您在 GAC 中引用程序集时,您必须通过其 strong name、其名称、版本号、文化(如果提供)以及公钥和数字签名 (程序集必须经过签名才能被视为强命名程序集,并且只能将强命名程序集添加到 GAC)。

如果您引用一个强命名的程序集,那么您已经在唯一地标识您希望使用的程序集。如果您引用的程序集不是强命名的,则该程序集无法加载到 GAC 中(并且 .Net 运行时无论如何也不会检查那里,请参阅 How the Runtime Locates Assemblies)。

如果您正在引用一个强命名的程序集(或者实际上是 any 程序集)并且想要接受该程序集的多个不同版本(例如 v1.0.0.0 和 v1.0.1.0),或者您想发布更新版本的程序集并允许现有应用程序继续运行而无需重新编译,那么您可以使用Assembly Binding Redirection

如果您希望能够引用一个程序集,而不管使用什么密钥签署该程序集,那么您最好根本不签署该程序集(因此不要将其添加到 GAC)。

我相信您也可以subscribe to the assembly resolve event,但是使用程序集绑定重定向是首选方法,只要它提供所需的行为。

【讨论】:

  • 你的意思是说我可以用同一个密钥(snk)一次又一次地用不同的版本构建程序集?
  • @Shashwat 是的,这实际上正是您应该做的。 snk 用于识别您(组件的公司/供应商),以证明实际上是您提供了该组件并且它没有被篡改。
  • 好的,知道了。但还有一个疑问。如果碰巧,我们会丢失那个 snk 文件;那么有没有办法像以前一样签署大会?因为 'sn -k Shape.snk' 只是创建一个随机键。
  • @Shashwat 不,那把钥匙很珍贵——不要松开它!
  • 哦!因此,我们的公司名称依赖于一个键。我认为必须有一些方法来保护它。其中之一可以创建多个副本。你有什么建议?
【解决方案2】:

编译时,您可以指定要使用的确切版本。这就是将在执行时加载的版本。如果您使用的是 Visual Studio,则引用的属性将包含版本号,以及表示是否必须加载确切版本号的标志。

【讨论】:

  • 但是(名称,版本)对仍然可以复制。
  • @Shashwat:程序集引用实际上还包括公钥令牌,但我不记得它是否在项目属性中可见。我相信,这个三元组在 GAC 中应该是独一无二的。
  • 但我永远不想过于具体地引用程序集。假设,我已经在某个地方部署了我的应用程序,并且它正在使用一个特定的程序集。现在,我只定期增强我的程序集,从而更改版本。但是我不想重新编译整个部署的应用程序(指定版本来加载程序集),那么它就不会加载我的程序集。
  • @Shashwat:那么你的要求是相互矛盾的——你的问题是如何强制 CLR 加载特定版本,而现在你说你不要想要强制它加载特定版本。您需要决定是否需要该控件。
  • @Shashwat:不,你不希望有。签署程序集的全部目的是证明您拥有密钥。将其存放在安全的地方。
【解决方案3】:

程序集由其名称、公钥令牌和版本定义。创建参考时,您可以具体并指明其中的每一个值。

【讨论】:

  • 但是假设,我已经在某个地方部署了我的应用程序并且它正在使用一个特定的程序集。现在,我只定期增强我的程序集,从而更改版本。但是我不想重新编译整个部署的应用程序(指定版本来加载程序集),那该怎么办?
  • 您可以执行程序集绑定重定向。您可以告诉您的应用程序,所有引用 My.Library.dll 版本 0.0.0.0 - 2.3.4.5 现在应该指向版本 2.4.0.0。这将是一个应用程序范围的重定向。只要签名没有改变,它就可以工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
  • 1970-01-01
  • 2010-12-14
  • 2010-10-17
相关资源
最近更新 更多