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


MSDN说:

  • AssemblyVersion :

指定要归属的程序集的版本。

  • AssemblyFileVersion :

指示编译器使用Win32文件版本资源的特定版本号。 Win32文件版本不需要与程序集的版本号相同。

  • AssemblyInformationalVersion :

定义程序集清单的其他版本信息。


这是使用装配属性的最佳做法的后续行动?


#1楼

值得注意的是其他一些事情:

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

在“其他版本信息”部分中,还有另一个名为“文件版本”的元素。 您可以在此处查看作为AssemblyFileVersion输入的内容。

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

此外,它不受AssemblyVersion的通配符替换。 如果您在AssemblyInfo.cs中只有一个值“3.0.1。*”,那么这正是将在其他版本信息 - >文件版本元素中显示的内容。

3)但我不知道安装程序使用除数字文件版本号之外的其他东西的影响。


#2楼

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

例如,使用asp.net core dotnet-cli打包的1.0.3。*的AssemblyVersion

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

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

CustomAttributeExtensions.GetCustomAttribute<AssemblyInformationalVersionAttribute>(asm);

#3楼

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

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

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


#4楼

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

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

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

其中,.NET唯一需要的是AssemblyVersion属性。 不幸的是,当它不加选择地改变时,它也会导致大多数问题,特别是如果你强烈命名你的程序集。


#5楼

的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) - 向微软报告 (未在VS2013中修复)。

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

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

[assembly: AssemblyInformationalVersion("1.0 RC1")]

#6楼

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

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

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

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

CLR不关心也不检查AssemblyFileVersion。

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

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

“例如,产品的2.0版本可能包含多个程序集; 其中一个程序集标记为1.0版,因为它是一个新的程序集,并未在同一产品的1.0版本中发布。 通常,您可以设置此版本号的主要部分和次要部分,以表示产品的公共版本。 然后,每次打包完整产品及其所有组件时,都会增加构建和修订部分。“ - Jeffrey Richter,[CLR通过C#(第二版)] p。 57

CLR不关心也不检查AssemblyInformationalVersion。

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

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.

我认为这种混淆的根源可能是因为微软原本打算对完整AssemblyVersion的这种严格匹配稍微宽松一点,只匹配Major和Minor版本部分:

“当加载程序集时,CLR将自动找到与所请求程序集的主要/次要版本匹配的最新安装服务版本。” - Jeffrey Richter,[CLR通过C#(第二版)] p。 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,[CLR来自C#(第二版)] p。 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的Major / Minor(破坏)和Build / Revision(非破坏)部分之间进行分离。

底线:仔细考虑何时更改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应用程序针对新版本重新编译!


#7楼

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