AssemblyVersion,AssemblyFileVersion和AssemblyInformationalVersion有什么区别?

时间:2020-03-05 18:53:56  来源:igfitidea点击:

有三个程序集版本属性。有什么区别?如果我使用AssemblyVersion并忽略其余部分,可以吗?

MSDN说:

  • AssemblyVersion:
Specifies the version of the assembly being attributed.
  • AssemblyFileVersion:
Instructs a compiler to use a specific version number for the Win32 file version resource. The Win32 file version is not required to be the same as the assembly's version number.
  • AssemblyInformationalVersion:
Defines additional version information for an assembly manifest.

这是"使用程序集属性的最佳实践是什么?"的后续文章。

解决方案

回答

Windows可以看到AssemblyVersion几乎保留在.NET内部。如果转到目录中的程序集的属性并切换到"版本"选项卡,则将在顶部看到" AssemblyFileVersion"。如果按版本对文件进行排序,这就是资源管理器所使用的。

" AssemblyInformationalVersion"映射到"产品版本",并且纯粹是"人类使用的"。

" AssemblyVersion"当然是最重要的,但是我也不会跳过" AssemblyFileVersion"。如果我们不提供AssemblyInformationalVersion,则编译器会通过剥离版本号的"修订"部分并保留major.minor.build来为我们添加它。

回答

当我们通过Windows资源管理器通过查看文件属性来查看文件的"版本"信息时,将显示" AssemblyInformationalVersion"和" AssemblyFileVersion"。这些属性实际上被编译到由编译器创建的" VERSION_INFO"资源中。

" AssemblyInformationalVersion"是"产品版本"值。 " AssemblyFileVersion"是"文件版本"值。

" AssemblyVersion"特定于.NET程序集,.NET程序集加载器使用它来了解要在运行时加载/绑定的程序集的哪个版本。

在这些之中,.NET绝对必需的唯一一个是AssemblyVersion属性。不幸的是,当随意更改时,它也会引起最多的问题,尤其是当我们强烈地命名装配时。

回答

AssemblyVersion

其他引用程序集的程序集将在哪里查找。如果此数字更改,其他程序集必须更新其对我们程序集的引用! AssemblyVersion是必需的。

我使用的格式是:major.minor。这将导致:

[assembly: AssemblyVersion("1.0")]

AssemblyFileVersion

用于部署。我们可以为每个部署增加此数字。安装程序使用它。用它来标记具有相同" AssemblyVersion"但从不同内部版本生成的程序集。

在Windows中,可以在文件属性中查看它。

如果可能的话,让它由MSBuild生成。 AssemblyFileVersion是可选的。如果未给出,则使用AssemblyVersion。

我使用的格式为:major.minor.revision.build,在其中将修订用于开发阶段(Alpha,Beta,RC和RTM),Service Pack和修补程序。这将导致:

[assembly: AssemblyFileVersion("1.0.3100.1242")]

AssemblyInformationalVersion

装配体的产品版本。这是我们与客户交流或者在网站上显示时使用的版本。该版本可以是字符串,例如" 1.0 Release Candidate"。

代码分析将对此有所抱怨(CA2243)-已报告给Microsoft(在VS2013中未修复)。

AssemblyInformationalVersion是可选的。如果未给出,则使用AssemblyFileVersion。

我使用以下格式:major.minor [revision as string]。这将导致:

[assembly: AssemblyInformationalVersion("1.0 RC1")]

回答

鉴于目前至少有三种方法可以为程序集指定版本,因此.NET中程序集的版本控制可能会令人困惑。

这是三个与版本相关的主要程序集属性:

// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]

按照约定,该版本的四个部分分别称为主要版本,次要版本,内部版本和修订版。

通常,我们将手动设置"主要"和"次要AssemblyFileVersion"以反映程序集的版本,然后在每次构建系统编译程序集时增加" Build"和/或者" Revision"。 AssemblyFileVersion应该允许我们唯一地标识程序集的内部版本,以便我们可以将其用作调试任何问题的起点。

在我当前的项目中,我们让构建服务器将来自源代码控制存储库的变更列表编号编码到AssemblyFileVersion的Build和Revision部分中。这样,我们就可以将构建服务器生成的任何程序集直接从程序集映射到其源代码(而不必在源代码管理中使用标签或者分支,也不必手动保留发布版本的任何记录)。

此版本号存储在Win32版本资源中,在查看程序集的Windows资源管理器属性页时可以看到。

CLR不关心也不检查AssemblyFileVersion。

AssemblyInformationalVersion旨在允许对整个产品进行一致的版本控制,该版本可能包含许多独立进行版本控制的程序集,可能具有不同的版本控制策略,并且可能由不同的团队开发。

“For example, version 2.0 of a product
  might contain several assemblies; one
  of these assemblies is marked as
  version 1.0 since it’s a new assembly
  that didn’t ship in version 1.0 of the
  same product. Typically, you set the
  major and minor parts of this version
  number to represent the public version
  of your product. Then you increment
  the build and revision parts each time
  you package a complete product with
  all its assemblies.”
             — Jeffrey Richter, [CLR via C# (Second Edition)] p. 57

CLR不关心也不检查AssemblyInformationalVersion。

CLR使用AssemblyVersion绑定到强命名的程序集。它存储在生成的程序集的AssemblyDef清单元数据表中,以及存储在引用该程序集的任何程序集的AssemblyRef表中。

这非常重要,因为这意味着在引用强命名程序集时,我们将紧密绑定到该程序集的特定AssemblyVersion。整个AssemblyVersion必须与绑定完全匹配才能成功。例如,如果在构建时引用强命名程序集的1.0.0.0版,但在运行时仅该程序集的1.0.0.1版可用,则绑定将失败! (然后,我们将不得不使用程序集绑定重定向解决此问题。)

为了加载程序集,整个AssemblyVersion是否必须完全匹配会有一些困惑。有些人错误地认为,AssemblyVersion的主要部分和次要部分必须匹配才能使绑定成功。这是一个明智的假设,但是最终是不正确的(从.NET 3.5开始),并且对于CLR版本验证这一点很简单。只需执行此示例代码。

在我的机器上,第二个程序集加载失败,并且融合日志的最后两行清楚地说明了原因:

.NET Framework Version: 2.0.50727.3521
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
Successfully loaded assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
Assembly binding for  failed:
System.IO.FileLoadException: Could not load file or assembly 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, 
PublicKeyToken=0b3305902db7183f' or one of its dependencies. The located assembly's manifest definition 
does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f'

=== Pre-bind state information ===
LOG: User = Phoenix\Dani
LOG: DisplayName = Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
 (Fully-specified)
LOG: Appbase = [...]
LOG: Initial PrivatePath = NULL
Calling assembly : AssemblyBinding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v2.0.50727\config\machine.config.
LOG: Post-policy reference: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
LOG: Attempting download of new URL [...].
WRN: Comparing the assembly name resulted in the mismatch: Revision Number
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

我认为造成这种混乱的原因可能是因为Microsoft最初打算通过只匹配主要版本和次要版本部分来对完整AssemblyVersion的这种严格匹配稍微宽一些:

“When loading an assembly, the CLR will automatically find the latest
  installed servicing version that
  matches the major/minor version of the
  assembly being requested.”
              — Jeffrey Richter, [CLR via C# (Second Edition)] p. 56

这是1.0 CLR的Beta 1中的行为,但是此功能在1.0发行版之前已被删除,并且尚未设法在.NET 2.0中重新出现:

“Note: I have just described how you
  should think of version numbers.
  Unfortunately, the CLR doesn’t treat
  version numbers this way. [In .NET
  2.0], the CLR treats a version number as an opaque value, and if an assembly
  depends on version 1.2.3.4 of another
  assembly, the CLR tries to load
  version 1.2.3.4 only (unless a binding
  redirection is in place). However,
  Microsoft has plans to change the
  CLR’s loader in a future version so
  that it loads the latest
  build/revision for a given major/minor
  version of an assembly. For example,
  on a future version of the CLR, if the
  loader is trying to find version
  1.2.3.4 of an assembly and version 1.2.5.0 exists, the loader with automatically pick up the latest
  servicing version. This will be a very
  welcome change to the CLR’s loader — I
  for one can’t wait.”
              — Jeffrey Richter, [CLR via C# (Second Edition)] p. 164 (Emphasis
  mine)

由于仍未实施此更改,因此我可以肯定地说,微软已经对此意图进行了追溯,现在更改此更改为时已晚。我试图在网上搜索这些计划的结果,但是找不到任何答案。我仍然想深入了解它。

因此,我给Jeff Richter发了电子邮件,直接问他,我想知道是否有人知道发生了什么事,那就是他。

他在12小时内(至少在星期六早上)进行了答复,并澄清说.NET 1.0 Beta 1加载程序确实实现了这种自动前滚机制,以获取程序集的最新可用生成和修订,但此行为在之前已得到恢复。 .NET 1.0已发布。后来打算恢复它,但在CLR 2.0发行之前并没有实现。然后是Silverlight,它是CLR团队的首要任务,因此此功能被进一步延迟了。同时,CLR 1.0 Beta 1时代的大多数人都已经搬走了,因此尽管已经付出了很多辛勤的工作,但这不太可能实现。

当前的行为似乎将持续下去。

从与Jeff的讨论中还值得注意的是,仅在删除自动前滚机制后才添加AssemblyFileVersion,因为在1.0 Beta 1之后,对AssemblyVersion的任何更改对客户来说都是重大更改,因此无处安全存储内部版本号。 AssemblyFileVersion是避风港,因为它从未被CLR自动检查。也许这样更清楚,它具有两个单独的版本号,分别具有不同的含义,而不是试图在AssemblyVersion的主要/次要(中断)和构建/修订(不中断)部分之间进行分隔。

道德是,如果我们要运送其他开发人员将要引用的程序集,则需要特别注意何时更改(和不更改)这些程序集的AssemblyVersion。对AssemblyVersion的任何更改都意味着应用程序开发人员将不得不根据新版本重新编译(以更新那些AssemblyRef条目),或者使用程序集绑定重定向手动覆盖该绑定。

  • 请勿将AssemblyVersion更改为旨在向后兼容的服务版本。
  • 对于已知有重大更改的发行版,请更改AssemblyVersion。

只需再看一看mscorlib上的版本属性:

// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]

请注意,其AssemblyFileVersion包含所有有趣的服务信息(此版本的Revision部分告诉我们所使用的Service Pack),同时AssemblyVersion固定为令人讨厌的旧版本2.0.0.0。对AssemblyVersion的任何更改都将强制每个引用mscorlib.dll的.NET应用程序针对新版本进行重新编译!