AssemblyVersion,AssemblyFileVersion 和 AssemblyInformationalVersion 有什么区别?

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


MSDN 说:


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

答案

AssemblyVersion

引用您的程序集的其他程序集的位置。如果此数字更改,其他程序集必须更新其对您程序集的引用! AssemblyVersion是必需的。

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

[assembly: AssemblyVersion("1.0")]

AssemblyFileVersion

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

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

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

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

[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旨在唯一地标识单个程序集的构建

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

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

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

CLR 不关心也不检查 AssemblyFileVersion。

AssemblyInformationalVersion旨在表示整个产品的版本

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

“例如,产品的 2.0 版可能包含多个程序集;这些程序集之一被标记为版本 1.0,因为它是同一产品的版本 1.0 中未提供的新程序集。通常,您设置此版本号的主要和次要部分以代表产品的公共版本。然后,每当将一个完整的产品及其所有组件打包在一起时,便会增加构建和修订零件。” —杰弗里 · 里希特(Jeffrey Richter),[通过 C#进行 CLR(第二版)]。 57

CLR 不关心也不检查 AssemblyInformationalVersion。

AssemblyVersion是 CLR 关心的唯一版本(但它关心整个AssemblyVersion

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

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

关于整个AssemblyVersion是否必须匹配的困惑。 (是的,它确实。)

为了加载程序集,整个 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 的这种严格匹配稍宽一些:

“在加载程序集时,CLR 将自动找到与所请求的程序集的主 / 次要版本匹配的最新安装服务版本。” —杰弗里 · 里希特(Jeffrey Richter),[通过 C#进行 CLR(第二版)]。 56

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

“注意:我刚刚描述了您应该如何看待版本号。不幸的是,CLR 不会这样处理版本号。 [在. NET 2.0 中,CLR 将版本号视为不透明值,并且如果程序集依赖于另一个程序集的 1.2.3.4 版本,则 CLR 尝试仅加载版本 1.2.3.4(除非已建立绑定重定向) )。但是, Microsoft 计划在将来的版本中更改 CLR 的加载程序,以便它为给定的主要 / 次要版本的程序集加载最新的构建 / 修订版 。例如,在 CLR 的将来版本中,如果加载程序试图查找程序集的版本 1.2.3.4,而存在版本 1.2.5.0,则加载程序将自动选择最新的维修版本。这将是对 CLR 加载程序的非常欢迎的更改 - 我迫不及待。” —杰弗里 · 里希特(Jeffrey Richter),[通过 C#进行 CLR(第二版)]。 164(强调点)

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

因此,我给 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。对 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 应用程序针对新版本进行重新编译!

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

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

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

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

AssemblyInformationalVersion是 “产品版本” 值。 AssemblyFileVersion是 “文件版本” 值。

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

其中,.NET 绝对必需的唯一AssemblyVersionAssemblyVersion属性。不幸的是,当随意更改时,它也会引起最多的问题,尤其是当您强烈地命名程序集时。

为了使这个问题保持最新,值得强调的是 NuGet 使用AssemblyInformationalVersion并反映了包括任何预发行后缀的软件包版本

例如,与 asp.net 核心 dotnet-cli 打包在一起的 AssemblyVersion 1.0.3。*

dotnet pack --version-suffix ci-7 src/MyProject

产生一个版本为 1.0.3-ci-7 的软件包,您可以使用以下方法进行反射检查:

CustomAttributeExtensions.GetCustomAttribute<AssemblyInformationalVersionAttribute>(asm);

值得一提的是:

1)如生成的程序集文件的 Windows 资源管理器 “属性” 对话框中所示,有两个地方称为 “文件版本”。在对话框标题中看到的那个显示的是 AssemblyVersion,而不是 AssemblyFileVersion。

在 “其他版本信息” 部分中,还有另一个元素称为 “文件版本”。在这里,您可以看到输入的 AssemblyFileVersion。

2)AssemblyFileVersion 只是纯文本。它不必符合 AssemblyVersion 的编号方案限制(例如, <65K)。如果愿意,它可以是 3.2。。您的构建系统将必须填写令牌。

而且,AssemblyVersion 不受通配符替换的限制。如果 AssemblyInfo.cs 中的值仅为 “3.0.1。*”,则这将恰好在 “其他版本信息”->“文件版本” 元素中显示。

3)我不知道使用数字文件版本号以外的内容对安装程序的影响。

更改程序集的 AssemblyVersion 时,如果它具有强名称,则需要重新编译引用程序集,否则将不会加载该程序集!如果它没有强名称,或者没有显式添加到项目文件中,则在构建时不会将其复制到输出目录,因此您可能会错过依赖的程序集,尤其是在清理输出目录之后。