Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nuget pack does not honor number of digits on assembly version

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.

like image 801
julealgon Avatar asked Jan 28 '15 14:01

julealgon


2 Answers

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.)

like image 153
Peas Avatar answered Nov 04 '22 01:11

Peas


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.

like image 42
Dave H Avatar answered Nov 04 '22 02:11

Dave H