问题
I need nuget pack
to generate a package version with only 3 digits (we want to do semantic versioning on it) but when I call it on a csproj which has an AssemblyVersion
attribute set to "1.0.0", the resulting nupkg file ends with version "1.0.0.0" in it's metadata (and file name). Why doesn't the command line tool honor the amount of digits specified on the AssemblyVersion
attribute?
I started this with a call to nuget spec
against the csproj file, which generates a stub nuspec file like this (it actually includes more tags with placeholder values, but I've deleted them since we don't need them):
<?xml version="1.0"?>
<package >
<metadata>
<id>$id$</id>
<version>$version$</version>
<title>$title$</title>
<authors>$author$</authors>
<owners>$author$</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<releaseNotes>Release notes.</releaseNotes>
<copyright>Copyright 2015</copyright>
</metadata>
</package>
With this nuspec file checked in TFS in the same folder as the csproj file, we can now call pack like this:
nuget pack MyProject.csproj
The project's AssemblyInfo.cs file contains a line to set the version explicitly:
[assembly: AssemblyVersion("1.0.0")]
It is all working perfectly fine, except for the fact that the tool is using 4 digits when it retrieves the assembly version. Even Windows shows the version with only 3 digits when I right click the dll on the file explorer and go to details. Why is NuGet using 4 digits? Am I perhaps missing something obvious?
Hardcoding the version in the nuspec is obviously not ideal, because then we would have to maintain the version number in two different places while they are intended to be always the same. I mean, this was supposed to be the idea behind the special placeholder value $version$
there that NuGet itself knows how to extract from the project.
回答1:
In the Creating and Publishing a Package it is stated that NuGet uses AssemblyVersionAttribute
attribute when the token $version$
is used.
Digging into NuGet source code, I've found that it's not as straight forward as one might think.
NuGet uses reflection to get your library's version. AssemblyName.Version
to be exact. Since all components of the version must be integers greater than or equal to zero (see AssemblyName.Version), the version presented is 1.0.0.0 (in your case) rather than 1.0.0 as declared in your AssemblyVersion
attribute.
Possible solution
The Nuspec Reference page adds more information next to the $version$
token. It mentions AssemblyInformationalVersionAttribute
attribute will get precedence over AssemblyVersionAttribute
. Using it will solve your problem.
Digging deeper
You might wonder why would AssemblyInformationalVersionAttribute
work and AssemblyVersionAttribute
won't?
The answer to that question is that NuGet uses CustomAttributeData.GetCustomAttributes(Assembly)
function to retrieve the attributes of your library, before it uses Assembly.Version. The above function will not list AssemblyVersionAttribute
, yet it will list AssemblyInformationalVersionAttribute
if it was used on the assembly.
Only then, if AssemblyInformationalVersionAttribute wasn't found, Assembly.Version will be used.
EDIT:
Relevant NuGet source code:
NuGet uses the following code to get the assembly version (if AssemblyInformationalVersionAttribute wasn't found):
Assembly assembly = Assembly.ReflectionOnlyLoadFrom(path);
AssemblyName assemblyName = assembly.GetName();
...
version = new SemanticVersion(assemblyName.Version);
The problem starts with assembly.GetName() as it creates and initializes AssemblyName with relevant parameters, including the version.
(That code can be found in AssemblyMetadataExtractor class, under public AssemblyMetadata GetMetadata(string path)
function.)
回答2:
Ran into this same problem and solved it using the "-version" attribute of nuget. It overrides the version from the nuspec file. Works wonderfully for semantic versioning.
Based on the above, I'm guessing it wasn't available at the time this discussion was started.
回答3:
NuGet seems to be using [assembly: AssemblyInformationalVersion()]
as a version, not AssemblyVersion
nor AssemblyFileVersion
Set AssemblyInformationalVersion
to 2 or 3 components and nuget will package it exactly as you specified
I'd also set AssemblyVersion
to some auto-incremented thing since it's used by .NET
and based on my MSBuild
experience it's safer to force it to think version changes all the time so it does not try to be smart about it
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyInformationalVersion("1.0")]
Results in
Project.1.0.nupkg
Containing
Project.dll
with metadata (as reported by ILSpy) ..., Version=1.0.6246.25505, Culture=neutral, PublicKeyToken=null...
So you get nice nuget version and fool proof assembly version (always changing so no weird caching during builds if package version stays the same, say for local testing)
Source
来源:https://stackoverflow.com/questions/28194498/nuget-pack-does-not-honor-number-of-digits-on-assembly-version