Today we are going to create our own NuGet package, publish it to Azure DevOps, and then consume it in our application. As our solution grows, it becomes important to break apart some of our dependencies. Sometimes these dependencies are common modules we want to share with other projects, or we may be developing a microservice and need to decouple dependencies from our solution.
In our example, currently all of our models are embedded in our web service project. As we start to look at using our website, we need to reference these models. Instead of adding a reference to our service, we are going to create new project, move our models into there, and then wrap this project into a private NuGet package. This NuGet package will be published to a private NuGet feed and then our projects will consume this NuGet package.
This adds some flexibility to our upgrade path – as a change to the model doesn’t need to be upgraded in all of the dependencies at the same time – we could for example upgrade our models NuGet package, and then consume the new version in the service, but not the website. As we have control over when to upgrade the NuGet package, we have more control over deciding when to upgrade the product.
Using NuGet packages like this is not perfect – it does reduce some agility, as changes to the model need to be published to a new version of the NuGet package before our application can consume them.
Creating the Models NuGet package
Our first step is to create a new .Net Standard class library project for our models. We add a new project to the solution, selecting the “Class Library (.NET Standard)” project template.
We name the project “SamLearnsAzure.Models”
In this new project, we copy the models folder and files from “SamLearnsAzure.Service”, fixing the name space in the files to
“SamLearnsAzure.Models”, and updating the references to our other projects to use this new project instead of the services namespace. We commit and push this into Azure Repos.
Creating the NuGet package feed
Next, in Azure DevOps, we browse to the Azure Artifacts section. As we haven’t setup any feeds yet, there is only the “New Feed” button, which we click.
In the “Create new feed” page, we add a new name for our feed, and leave the options at their current defaults – most projects don’t need to customize these, but in a private situation, you may decide to limit visibility.
With the feed created, it’s time to connect – we click the “Connect to feed” button
In the popup that appears, all we really need is the “Package source URL”, which we copy and save for later. The information to push packages to NuGet we don’t need as we will use Azure DevOps to build and push our packages.
Pushing our package to NuGet with DevOps
Now that we have a feed to publish our package into, let us create a new build and release process. First we need to create a new YAML file to build the package. You can view the entire YAML file here.
- The version variable on line 10 is very important – this is how we version our package. Packages are immutable, which means they can’t be updated or replaced. Therefore versions need to be unique and sequential. There are a number of strategies for managing versioning in packages, we are trying to automate as much as possible. Here we can manually update major and minor versions to represent bigger changes, and then append the “build.buildid” variable to automatically increment the version and ensure a unique version of our models is pushed to our NuGet feed. Each build increments the “build.buildid” variable.
- Lines 13 to 32 are our standard .NET core restore, build and publish YAML commands
- On line 34, we use “dotnet pack” to package our code into a NuGet package. Here you can see we’ve used the “byEnvVar” option to specify the version with an environment variable – the variable we defined on line 10. Note that this requires a Windows host and doesn’t currently work in a Linux host.
To reference a YAML file we’ve already created, we browse to Azure Pipelines and create a new build, selecting the “Use the visual designer” option.
In the new build, we select the “YAML” template.
Then in the new build settings, we name our build “SamLearnsAzure-Package-CI”, select the “Hosted VS2017” build, and add the YAML file we created earlier. The build has been successfully setup!
Next we start a new release, naming it “Models Package Release”, adding the artifact for the “SamLearnsAzure-Package-CI” build that was just successfully built, and naming the environment “NuGet Feed”.
In the tasks, we add a “NuGet” task, that will help us to push our package to our feed.
In the NuGet task, we select the command “Push”, and specify a path to the our NuGet package. Note the “*.nupkg” in this path – this wildcard will push any NuGet package that is present, rather than a specific version. Finally, we target our “SamLearnsAzurePackageFeed” we created earlier.
Back in Azure Artifacts, we can click on our feed and see the “SamLearnsAzure.Models” versions we have successfully deployed to our feed.
Connecting to our feed in Visual Studio
With the feed setup and our package successfully published, it’s time to connect to the feed and start consuming our NuGet packages in Visual Studio. We right click on our solution and select “Manage NuGet Packages”. In the dialog that appears, we click on the gear/cog in the top right.
This opens an “Options” popup, where we can configure the package sources. We click the green plus in the top right to add a new package source.
This new package source is filled with default values, we need to configure it.
We name the source, “SamLearnsAzurePackageFeed”, and add the source json document from our feed that we had previously noted for later: “https://samsmithnz.pkgs.visualstudio.com/_packaging/SamLearnsAzurePackageFeed/nuget/v3/index.json”
Now we have connected to our NuGet feed, we can remove all direct references to “SamLearnsAzure.Models” in our solution, and then in those projects, add our new NuGet package instead.
Today we created our own NuGet feed, published our own package into it, and then consumed it into our projects. We learned about how to version our packages, and the value of having our models decoupled.
Building Nuget packages is a useful skill to understand if you have a common module that is shared in many projects. NuGet adds versioning, and allows us to share the package privately or publicly as needed. While we’ve used NuGet packages today, but these same concepts could also be used to create NPM or Maven packages.
- Azure Pipelines for NuGet: https://docs.microsoft.com/en-us/azure/devops/pipelines/artifacts/nuget?view=azure-devops&tabs=yaml
- Feature Image credit: https://mitchdenny.com/universal-packages/