Testing NuGet packages in local development

In an ideal world, when developing a NuGet package you can easily verify it works during local development.

For simple / code-only NuGet packages it's easy, just use a project reference:

<ProjectReference Include= "MyPackage">

But, if your package contains additional content, and-or build scripts a ProjectReference may not be sufficient.

It's particularly troublesome when you have MSBuild scripts. You can 'almost' solve the issue by importing the packages MSBuild scripts, but that has its own problems.

NuGet issue 6579 includes a discussion of various approaches and problems when trying to test local packages.

After scouring the net for ideas and approaches, here is my current setup for testing a NuGet package locally:

# A couple of demo projects to use
dotnet new classlib -o src/MyPackage -n MyPackage
dotnet new console -o samples/UseMyPackage -n UseMyPackage

Edit src/MyPackage.csproj

<PropertyGroup>
  <!--Output package to samples -->
  <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  <PackageOutputPath>../../samples/packages</PackageOutputPath>
  <!--developer always builds with bigger then actual package version -->
  <VersionPrefix>99.0.0</VersionPrefix>
</PropertyGroup>

<Target Name="AfterPack" AfterTargets="Pack">
    <!--reset local falback cache (if any)-->
    <RemoveDir Directories="$(PackageOutputPath)/$(PackageId)/" />
  </Target>

Add custom samples/NuGet.config :

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <!--Setup global cache to local folder.-->
    <add key="globalPackagesFolder" value="./packages/"/>
  </config>
  <packageSources>
    <!--Add package output as a source.-->
    <add key="local" value="./packages" />
  </packageSources>
  <fallbackPackageFolders>
    <!--Restore current global packages as a fallback folder-->
    <add key="DefaultGlobalsWin" value="%HOME%/.nuget/packages" />
  </fallbackPackageFolders>
</configuration>

Note : you will need the %HOME% environment variable on windows, set it to %USERPROFILE%

Finally, build and add a reference to your package

 dotnet build src/MyPackage

 dotnet add samples/UseMyPackage package MyPackage -v 99.0.0
 dotnet build samples/UseMyPackage

Updating during development

Now to test its use.

Add src/MyPackage/build/MyPackage.targets

<Project>
  <Target Name="Demo" AfterTargets="build">
    <Message Importance="High" Text="Package targets imported" />
  </Target>
</Project>

Update src/MyPackage/MyPackage.csproj

<ItemGroup>
 <Content Include="build/**" target="build" Pack="true" PackagePath="%(Identity)" />
 <UpToDateCheckInput Include="build/**" />
 <UpToDateCheckOutput Include="$(PackageOutputPath)/$(PackageId).nupkg"/>
</ItemGroup>
#rebuild package
dotnet build src/MyPackage

# rebuild demo
dotnet build samples/UseMyPackage

You should see 'Package targets imported' in the build for UseMyPackage

How it works.

The samples/NuGet.config sets up samples/packages as BOTH a package source and the global fallback folder.

The global fallback is used to cache downloaded packages. So setting it local to our project makes it easier to clean.

There's nothing special about the global fallback folder, except it's the first. So we can re-use the default and avoid re-downloading packages you already have.

Whenever I build MyPackage it clears the local (global) fallback folder and writes an updated MyPackage.nupkg

To make sure MyPackage re-builds properly, use UpToDateCheckInput and UpToDateCheckOutput; for more info on these see up-to-date-check

Now when building samples/UseMyPackage it can't find a local unpacked version of MyPackage; so it restores it.

And since samples/packages is the only source for version 99.0.0; that's where it's going to get the package from.

And since samples/packages is the global fallback; NuGet will un-pack and cache it there, making it trivial to clean the local (global) fallback on next MyPackage build.

Limitations

The NuGet.config needs to be positioned so it doesn't mess up other builds. This constrains the folder structure you can use.

On occasion, I have found I may need to re-build the UseMyPackage project. Particularly when using Visual Studio, a cache somewhere I think.