Step-by-Step Guide to NuGet Package Generation

Nuno Cancelo
7 min readApr 2, 2024

--

How to create a dotnet nuget package.

Developing software solutions is always challenging, and soon enough we get a lot of code and logic applied to it. Sometimes you reach the point where you notice that you are copying and pasting the same code over and over projects and solutions. Even when it isn’t boring enough, you find out that the code copied has a bug, now the question remains: how many projects do we have to fix this bug?

This article is a step-by-step tutorial on how to create a code library and reuse it across projects safely.

Prerequisites

Before we begin, make sure you have the following installed on your machine:

  1. .NET Core SDK (6 or later).
  2. Visual Studio or Visual Studio Code (optional but recommended).

I’m using .NET SDK 8, and Visual Studio 2022. But it is a bit irrelevant. You must be comfortable with the tools while following the article.

Step 1: Creating the Solution

I’m going to start by creating a new solution project, so we go straight to Visual Studio and do the rest of the configuration.

Open a Terminal Console:

$> dotnet new sln -n DotnetNugetArticle

Open the Visual Studio and load the just created empty solution.

Step 2: Setting Up the Project

From my experience, the most important concept to keep in mind is structure. If you keep your project properly structured, you can reproduce the recipe repeatedly having the same behaviour By having the projects and solutions with the same structure you can automate the artefact generation following the same recipe, and you can even create a new template that has that same structure. But that is another article. :)

I’m going to add two solution folders:

  • src: where all the projects will be laid down.
  • tests: where all the tests of the project will be.

Now I’m creating at solution level the following files:

  • CHANGELOG.md: We will keep the history of the project.
  • Directory.Build.props: We will have the metadata of our project.
  • LICENSE: The open-source license that we have. MIT License in this case.
  • README.md: Information file about the project.

There are other files that we can add:

  • .gitignore: Git ignore file.
  • .editorconfig: IDE file with the rules and code styles to be applied to the project.
  • global.json: Define which .NET SDK version is used.
  • nuget.config: Defines the source of the package.

Note:

Although Windows systems are case-insensitive, Linux systems are not. So is very important that the filenames are in the proper case, such as Directory.Build.props. Always confirm the filenames with the documentation before applying automatisms.

By now the solution structure should look like this:

You should also upload an image to be the icon of the library and call it icon.64.png. If you use images with attribution requirements, that should be given and added to the README.md file.

Step 3: Setting up the Metadata

The metadata of the solution is what is going to be fundamental to describe the NuGet file. With the SDK project, we can add that metadata to the csproj file. But if our solution has 10 project libraries, anytime we want to upgrade or make a change, we have to make it on 10 different files. And that is boring.

A simpler way is to keep the metadata on the Directory.Build.props on the root of the solution, and that metadata will be applied to all projects underneath.

Directory.Build.props Template

<Project>
<PropertyGroup>
<VersionPrefix></VersionPrefix>
<Authors></Authors>
<PackageIcon></PackageIcon>
<PackageLicenseExpression></PackageLicenseExpression>
<PackageReadmeFile></PackageReadmeFile>
<RepositoryUrl></RepositoryUrl>
<PackageProjectUrl></PackageProjectUrl>
<RepositoryType></RepositoryType>
<RepositoryBranch></RepositoryBranch>
<Title></Title>
<Description></Description>
<PackageTags></PackageTags>
</PropertyGroup>
<ItemGroup>
<None Include="" Pack="true" PackagePath="\" />
</ItemGroup>
</Project>

Although only a handful of fields are mandatory, you should fill in as much as you can with relevant information.

Directory.Build.props filled example

<Project>
<PropertyGroup>
<VersionPrefix>1.1.0</VersionPrefix>
<Authors>Nuno Cancelo</Authors>
<PackageIcon>icon.64.png</PackageIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/masterzdran/payment-required</RepositoryUrl>
<PackageProjectUrl>https://github.com/masterzdran/payment-required</PackageProjectUrl>
<RepositoryType>git</RepositoryType>
<RepositoryBranch>main</RepositoryBranch>
<Title>PaymentRequirement</Title>
<Description>A library that add a middleware to validate if a payment is due, to use SaaS service.</Description>
<PackageTags>Payment Required</PackageTags>
</PropertyGroup>
<ItemGroup>
<None Include="../../../icon.64.png" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<None Include="../../../README.md" Pack="true" PackagePath="\"/>
</ItemGroup>
</Project>

The result, by inspection (NuGet Package Explorer):

As you can see, the package has most of the fields filled which will give you library consumers more confidence in using. The missing fields are related to linking the source to the code, for debug purposes.

Two fields are crucial here. The Id field and the Version field.

The Id field must be unique within all the NuGet libraries in the world, so it is very important that read the documentation and establish a unique naming convention for the package Id.

The Version field should follow the semantic versioning because once the NuGet is published, you CAN’T reuse that version.

Step 4: Create the Library Project

Now you can create a new “Class Library” project within the src solution folder. When “Configure your new project” give a name in the “Project Name” and in the location (this is very important) you should click on the three dots, create a src folder and select that folder as destiny:

The structure of the solution should be the same on the filesystem. This approach will simplify your life over time.

Note

I’ll use one of my open-source projects as source code, to keep the focus on what is important.

The “Class Library” project is created, and now is time to do the code to be distributed.

Now we have to decide which frameworks we want our library to be compatible with. The most compatible target framework is .NET Standard 2.0, which will work with .NET Framework and .NET Core. While .NET Standard 2.1, will work with .NET Core, but not with .NET Framework.

You can also target only specific versions, it is your choice.

For this article, the library will be targeted to .NET Standard 2.0 and .NET Standard 2.1 (just because we can :) ), so we opened the project csproj and made some changes:

By default, line 4 will have the element “TargetFramework” and have one specific framework. To allow multiple frameworks, we need to change to “TargetFrameworks” and add the frameworks separated with a semicolon (;).

That is it. Now the project is ready to be packed.

Step 5: Pack the Project

Our library is ready, our tests are done, everything is fine and we are ready to create our NuGet file.

Open a terminal on the root of the solution, and type:

$> dotnet pack  --configuration Release --output ./dist/

This command will pick the solution file, build the solution and pack the projects that are packable, leaving the artefact in the dist folder.

This is an example of a possible output:

If we inspect the NuGet file again, we should have something like this:

Our packed library with two defined targets: .NET Standard 2.0 and .NET Standard 2.1

That is it!

Step 6: Publishing the NuGet File

We have a NuGet file, but if we don’t publish it somewhere, the developer can’t use it. There are many solutions for NuGet feeds, public and private, paid and free. The most common one is NuGet.Org.

The process is similar in all of them. To publish the NuGet, apply the following command:

$> dotnet nuget push dist/paymentrequired.*.nupkg --api-key ${{secrets.NUGET_ORG_TOKEN}} --source https://api.nuget.org/v3/index.json

You need a NuGet.Org account and generate a token to be able to upload the artefact.

Conclusion

This article is an overview, and a step-by-step tutorial to create a NuGet package, by following some good practices and some lessons learned from my errors. There are other concerns that you should be aware like the package id strategy, or creating build, test, pack, publish pipelines and keep your secrets private.

Automation is the best practice, keeping a clean structure will assist you in a long way.

The semantic versioning could be automatic (with proper Git Workflow) however, I believe is safer if you change the version manually in the Directory.Build.props file.

References

--

--

Nuno Cancelo
Nuno Cancelo

Written by Nuno Cancelo

Senior Software Engineer | Dev Lead | Tech Lead | Code Cleaner | Community Leader | Puzzle Solver | Dev Evangelist | Beer Lover

No responses yet