有三个程序集版本属性。有什么区别?如果我使用AssemblyVersion
其余部分,可以忽略吗?
MSDN说:
-
指定要赋予属性的程序集的版本。
-
指示编译器对Win32文件版本资源使用特定的版本号。Win32文件版本不需要与程序集的版本号相同。
-
定义程序集清单的其他版本信息。
这是“使用程序集属性的最佳实践是什么?”的后续文章。
有三个程序集版本属性。有什么区别?如果我使用AssemblyVersion
其余部分,可以忽略吗?
MSDN说:
指定要赋予属性的程序集的版本。
指示编译器对Win32文件版本资源使用特定的版本号。Win32文件版本不需要与程序集的版本号相同。
定义程序集清单的其他版本信息。
这是“使用程序集属性的最佳实践是什么?”的后续文章。
Answers:
AssemblyVersion
其他引用您的程序集的程序集将在哪里查找。如果此数字更改,则其他程序集必须更新其对您程序集的引用!如果它破坏了向后兼容性,则仅更新此版本。将AssemblyVersion
是必需的。
我使用格式:major.minor。这将导致:
[assembly: AssemblyVersion("1.0")]
如果严格遵守SemVer,则意味着仅在主要更改(即1.0、2.0、3.0等)发生变化时才进行更新。
AssemblyFileVersion
用于部署。您可以为每个部署增加此数字。安装程序使用它。使用它来标记具有相同AssemblyVersion
,但是从不同内部版本生成的程序集。
在Windows中,可以在文件属性中查看它。
AssemblyFileVersion是可选的。如果未给出,则使用AssemblyVersion。
我使用以下格式:major.minor.patch.build,在前三部分中遵循SemVer,在后一部分中使用构建服务器的内部版本号(本地构建为0)。这将导致:
[assembly: AssemblyFileVersion("1.3.2.254")]
请注意,System.Version将这些部分命名为major.minor.build.revision
!
AssemblyInformationalVersion
装配体的产品版本。这是您与客户交流或在您的网站上显示时使用的版本。这个版本可以是字符串,例如' 1.0 Release Candidate '。
该AssemblyInformationalVersion
是可选的。如果未给出,则使用AssemblyFileVersion。
我使用以下格式:major.minor [.patch] [修订为字符串]。这将导致:
[assembly: AssemblyInformationalVersion("1.0 RC1")]
major.minor[.build[.revision]]
,但不是major.minor.revision.build
在给定的答案中,版本号和修订号会被交换System.Reflection.Assembly.GetExecutingAssembly().GetName().Version
。
AssemblyInformationalVersion
,如果省略,AssemblyFileVersion
则使用。然后, AssemblyVersion
如果两者都省略。
鉴于目前至少有三种方法可以为程序集指定版本,因此.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条目),或者使用程序集绑定重定向手动覆盖该绑定。
只需再看一看mscorlib的version属性:
// 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
AssemblyFileVersion
Windows 几乎可以看到。如果转到目录中的程序集的属性并切换到“版本”选项卡,则将AssemblyFileVersion
在顶部看到。如果按版本对文件进行排序,这就是资源管理器所使用的。
该AssemblyInformationalVersion
映射到“产品版本”,其目的是纯粹“以人使用”。
AssemblyVersion
当然是最重要的,但我也不会跳过AssemblyFileVersion
。如果您不提供AssemblyInformationalVersion
,则编译器会通过剥离版本号的“修订”部分并留下major.minor.build来为您添加它。
AssemblyInformationalVersion
AssemblyFileVersion
当您通过Windows资源管理器通过查看文件属性来查看文件的“版本”信息时,将显示。这些属性实际上被编译到VERSION_INFO
由编译器创建的资源中。
AssemblyInformationalVersion
是“产品版本”值。AssemblyFileVersion
是“文件版本”值。
的AssemblyVersion
是特定于.NET组件,并且用于由.NET组件装载器知道到加载/绑定在运行时,其一个组件的版本。
在这些AssemblyVersion
属性中,.NET绝对必需的唯一属性是。不幸的是,当随意更改它时,它也会引起最多的问题,尤其是当您强烈地命名程序集时。
为了使这个问题保持最新,值得重点介绍一下AssemblyInformationalVersion
NuGet所使用的内容,它反映了包括任何预发行后缀的软件包版本。
例如,与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所做的编号方案限制(例如,<build> <65K)。如果愿意,它可以是3.2。<release tag text>。<datetime>。您的构建系统将必须填写令牌。
而且,AssemblyVersion不受通配符替换的限制。如果AssemblyInfo.cs中的值仅为“ 3.0.1。*”,则这恰好将在“其他版本信息”->“文件版本”元素中显示。
3)我不知道使用数字文件版本号以外的内容对安装程序的影响。