提问



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





MSDN说:



  • 的AssemblyVersion:[34]



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


  • 的AssemblyFileVersion:[35]



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


  • AssemblyInformationalVersion:[36]



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







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

最佳参考


的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中修复)。[38]


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


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


[assembly: AssemblyInformationalVersion("1.0 RC1")]

其它参考1


在.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版本在运行时可用,则绑定将失败! (然后,您必须使用程序集绑定重定向解决此问题。)[39]


对整个AssemblyVersion是否必须匹配感到困惑。 (是的,确实如此。)



围绕整个AssemblyVersion是否必须完全匹配以便加载程序集存在一些混淆。有些人错误地认为,只有大会版本的主要部分和次要部分必须匹配才能使约束成功。这是一个明智的假设,但它最终是不正确的(从.NET 3.5开始),并且为您的CLR版本验证这一点是微不足道的。只需执行此示例代码。[40]


在我的机器上,第二个程序集加载失败,并且融合日志的最后两行使得它非常清楚原因:


.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版(除非有约束力
  重定向到位了)。然而,
  微软计划改变
  CLR的装载机在未来的版本中如此
  它加载最新的
  给定主要/次要的构建/修订
  程序集的版本
。例如,
  在CLR的未来版本上,如果是
  loader正试图找到版本
  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应用程序针对新版本重新编译!

其它参考2


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


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


AssemblyVersion肯定是最重要的,但我也不会跳过AssemblyFileVersion。如果你不提供AssemblyInformationalVersion,编译器会通过剥离修订版为你添加它AssemblyInformationalVersion。一段你的版本号并离开major.minor.build。

其它参考3


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


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


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


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

其它参考4


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


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


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


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


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


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

其它参考5


为了使这个问题保持最新,值得强调的是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);

其它参考6


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