Long gone are the days we had to pay to host our
NuGet packages. Today, things
have changed. We have many options to host our own NuGet packages for free
(including privately if we wish) including in our own
GitHub repositories. On this
tutorial let's review how to build our own packages using
.NET Core's CLI, push them to
GitHub and finally, how to consume from our own projects.
About NuGet
NuGet is a free and open-source package manager designed by Microsoft and used
extensively in the .NET /.NET Core ecosystem. NuGet is the name of the tool
and of the package itself. The most common repository for NuGet packages is
NuGet.org hosting more
than 200k packages! But we can host our own packages on different repos
(including private ones) such as
GitHub Packages. NuGet is bundled with
Visual Studio
and with the
.NET Core SDK
so you probably have it already available on your machine.
About GitHub Packages
GitHub Packages
is GitHub's free offering for those wanting to host their own packages. GitHub
Packages allows hosting public and private packages. The benefits of using
GitHub Packages is that it's free, you can share your packages privately or with the rest of the world, integrate with
GitHub APIs, GitHub Actions, webhooks and even create complex end-to-end
DevOps workflows. For more information about GitHub Packages,
click here.
Why build our own packages
But why build our own packages? Mainly because packages simplify using and
distributing self-contained and reusable software (tools, libraries, etc) in a
clean and organized way of doing so. Beyond that, other common reasons are:
- sharing packages with someone else (and possibly the world)
-
sharing that package privately with your coworkers so they can be used in
different projects.
-
packaging software so it can be installed or deployed elsewhere.
Building NuGet Packages
So let's get started and build our first NuGet package. The project we'll
build is a simple library consisting of
POCOs
I frequently use as
standard onfiguration bindings
when developing microservices:
Smtp,
Redis,
RabbitMQ,
MassTransit and
MongoDB. I chose this
example because this is the type of code we frequently duplicate, so why not
isolate them in a shareable package and keep
our codebase
DRY?
Creating our project
To quickly create my project let's use the
.NET Core CLI (feel free to use
Visual Studio if you will):
dotnet new classlib -o HildenCo.Core
Then I'll add those config classes. For example the
SmtpOptions looks like:
public class SmtpOptions
{
public string Host {
get; set; }
public int Port { get; set; }
public string Username { get; set; }
public string
Password { get; set; }
public string FromName { get;
set; }
public string FromEmail { get; set; }
}
Creating our first NuGet package
Let's then create our first package. The simplest way to do so is by
configuring it via Visual Studio. For that, select the Project and Alt-Enter
it (or right-click it with the mouse) to view Project Properties and
check Generate NuGet package on build on the Package tab:
Don't forget to add relevant
information about your package such as Id, Name, Version, Authors, Description,
Copyright, License and RepositoryUrl. All that information is required by GitHub:
If you prefer, you can edit the above metadata directly in the csproj file.
Now, build again to confirm our package was built by inspecting the
Build Output in VS (Ctrl-W, O):
1>------ Build started: Project: HildenCo.Core, Configuration: Debug Any
CPU ------
1>HildenCo.Core ->
C:\src\nuget-pkg-demo\src\HildenCo.Core\bin\Debug\netstandard2.0\HildenCo.Core.dll
1>Successfully created package
'C:\src\nuget-pkg-demo\src\HildenCo.Core\bin\Debug\HildenCo.Core.0.0.1.nupkg'.
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped
==========
Congrats! You now have built your first package!
Don't forget to add RepositoryUrl with your correct username/repo name.
We'll need it to push to GitHub later.
Creating our package using the CLI
As always, the CLI may be a better alternative. Why? In summary because it
allows automating package creation on
continuous integration,
integrating with APIs, webhooks and even creating end-to-end DevOps workflows.
So, go ahead and uncheck that box and build it again with:
dotnet pack --configuration Release
This time, we should see this as output:
Microsoft (R) Build Engine version 16.6.0+5ff7b0c9e for .NET Core
Copyright
(C) Microsoft Corporation. All rights reserved.
Determining
projects to restore...
All projects are up-to-date for restore.
HildenCo.Core ->
C:\src\nuget-pkg-demo\src\HildenCo.Core\bin\Release\netstandard2.0\HildenCo.Core.dll
Successfully created package
'C:\src\nuget-pkg-demo\src\HildenCo.Core\bin\Release\HildenCo.Core.0.0.1.nupkg'.
TIP: You may have realized that we now built our package as release. This is
another immediate benefit from decoupling our builds from VS. On rare
occasions should we push packages built as Debug.
Pushing packages to GitHub
Generating an API Key
In order to authenticate to GitHub Packages the first thing we'll need is an
access token. Open your GitHub account, go to Settings -> Developer
Settings ->
Personal access tokens, click
Generate new Token, give it a name, select
write:packages and save:
Creating a nuget.config file
With the API key created, let's create our
nuget.config file. This file
should contain the authentication for the package to be pushed to the remote
repo. A base config is listed below with the fields to be replaced in bold:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add
key="github"
value="https://nuget.pkg.github.com/<your-github-username>/index.json"
/>
</packageSources>
<packageSourceCredentials>
<github>
<add key="Username" value="<your-github-username>" />
<add key="ClearTextPassword" value="<your-api-key>" />
</github>
</packageSourceCredentials>
</configuration>
Pushing a package to GitHub
With the correct configuration in place, we can push our package to GitHub
with:
dotnet nuget push ./bin/Release/HildenCo.Core.0.0.1.nupkg --source "github"
This is what happened when I pushed mine:
dotnet nuget push ./bin/Release/HildenCo.Core.0.0.1.nupkg --source "github"
Pushing
HildenCo.Core.0.0.1.nupkg to 'https://nuget.pkg.github.com/hd9'...
PUT https://nuget.pkg.github.com/hd9/
OK
https://nuget.pkg.github.com/hd9/ 1927ms
Your package was pushed.
Didn't work? Check if you added RepositoryUrl to your project's
metadata as nuget uses it need it to push to GitHub.
Reviewing our Package on GitHub
If you managed to push your first package (yay!), go ahead and review it in
GitHub on the Package tab of your repository. For example, mine's available
at:
github.com/hd9/nuget-pkg-demo/packages
and looks like this:
Using our Package
To complete the demo let's create an ASP.NET project to use our own package:
dotnet new mvc -o TestNugetPkg
To add a reference to your package, we'll use our own
nuget.config since it contains
pointers to our own repo. If your project has a solution, copy the
nuget.config to the solution folder. Else, leave it in the project's
folder. Open your project with Visual Studio
and open the Manage NuGet Packages. You should see your newly created
package there:
Review the logs to make sure no errors happened:
Restoring packages for C:\src\TestNugetPkg\TestNugetPkg.csproj...
GET https://nuget.pkg.github.com/hd9/download/hildenco.core/index.json
OK https://nuget.pkg.github.com/hd9/download/hildenco.core/index.json 864ms
GET
https://nuget.pkg.github.com/hd9/download/hildenco.core/0.0.1/hildenco.core.0.0.1.nupkg
OK
https://nuget.pkg.github.com/hd9/download/hildenco.core/0.0.1/hildenco.core.0.0.1.nupkg
517ms
Installing HildenCo.Core 0.0.1.
Installing NuGet package
HildenCo.Core 0.0.1.
Committing restore...
Writing assets file to
disk. Path: C:\src\TestNugetPkg\obj\project.assets.json
Successfully
installed 'HildenCo.Core 0.0.1' to TestNugetPkg
Executing nuget actions
took 960 ms
Time Elapsed: 00:00:02.6332352
========== Finished
==========
Time Elapsed: 00:00:00.0141177
========== Finished
==========
And finally we can use it from our second project and harvest the benefits of clean code
and code reuse:
Final Thoughts
On this post we reviewed how to build our own
NuGet packages using
.NET Core's CLI, pushed them to
GitHub and finally described how to consume them from our own .NET projects.
Creating and hosting our own NuGet packages is important for multiple reasons
including sharing code between projects and creating deployable artifacts.
Source Code
See Also