After my previous post on upgrading my project to compile with .NET Core, I found some unexpected issues compiling my NuGet package.

Previously, I’d used NuGet to do the packing of the package, using this task:

Task Compile.NuGet -Depends Requires.NuGet, Requires.BuildType,
        Requires.BuildDir, Compile.Assembly, Configure.PackagesFolder {

    $nugetFolder = join-path $packagesFolder Niche.CommandLine
    mkdir $nugetFolder | Out-Null

    $csprojFile = resolve-path .\src\Niche.CommandLine\Niche.CommandLine.csproj

    exec {
        & $nugetExe pack $csprojFile -version $semver10 
            -outputdirectory $packagesFolder -basePath $buildDir 
            -properties Configuration=$buildType
    }
}

Unfortunately, this approach broke in nasty ways after I’d updated the projects to .NET Core - there seems to be a nuget.exe incompatibility with the new .csproj format. Worse than that, the error message itself is completely unhelpful:

Unable to cast object of type 'System.String' to type 'NuGet.Frameworks.NuGetFramework'.

I easily found a number of different ways to make the packaging work (the most often cited were dotnet pack and msbuild /t:pack), but none of them seemed to allow easy control over the version number used. It seemed odd to me that such a simple thing could be so difficult to achieve.

Eventually, I discovered a key pair of facts:

  • The dotnet pack command uses msbuild under the hood and will pass on property values defined with /property when msbuild is run.
  • The version of a NuGet package can be specified within a .csproj file by defining the property PackageVersion within the project file.

Putting these two together, I was able to control the version number of a generated package by defining PackageVersion on the command line:

dotnet pack sample.csproj /property:PackageVersion=4.3.2

Updating my psake build script, I modified the Compile.NuGet task to this:

Task Compile.NuGet -Depends Requires.DotNet, Requires.BuildType,
        Requires.BuildDir, Compile.Assembly, Configure.PackagesFolder {

    $nugetFolder = join-path $packagesFolder Niche.CommandLine
    mkdir $nugetFolder | Out-Null

    $csprojFile = resolve-path .\src\Niche.CommandLine\Niche.CommandLine.csproj

    exec {
        & $dotnetExe pack $csprojFile
             --output $packagesFolder
            /property:PackageVersion=$semver20 
            /property:Configuration=$buildType 
            /fileLogger
            /flp:verbosity=detailed`;logfile=$buildDir\Niche.CommandLine.nuget.log
    }
}

Note that I’ve also changed the packaging task to use the SemVer 2.0 version - in the interim between writing these two blog posts, Nuget.org has announced full support for the new version of semantic versioning! The sticking point has always been that older NuGet clients might crash on version numbers using SemVer 2.0 - they’ve worked out how to identify those clients and will hide pre-release SemVer 2.0 packages from those clients. Nice.

Prior post in this series:
.NET Core Builds
Next post in this series:
The day my build broke

Comments

blog comments powered by Disqus