Azure DevOps - Always Be Shipping!

Azure DevOps – how to package a single DLL?

This post was most recently updated on December 29th, 2021.

2 min read.

Okay – a quick piece of documentation that was a bit lackluster, so it’s again a good idea to log somewhere. How to package a simple DLL that’s a result of your Azure DevOps Pipeline?

In my particular case, I have configured a post-build step to obfuscate the DLL, that’s first built by MSBuild. That works nicely. However, the default way to create a NuGet package, where you select a project (usually you pass the same variable to NuGet pack command that you used earlier for your VSBuild command), doesn’t work here: instead, you need to specify a nuspec file.

What’s a nuspec file?

A nuspec file is an XML manifest file, that contains the metadata for a NuGet package. In our case, it’s used by the Azure DevOps build pipeline to pack our solution into an actual NuGet package, that can then be pushed to a package stream or distributed some other way.

While Visual Studio doesn’t have a template for it out-of-the-box, you can just create an empty file, copy-paste the template below into it and replace the node values with your own:

<pre lang="xml">
<?xml version="1.0"?>
<package>
  <metadata>
    <id>[yournugetname]</id>
    <version>[semver-compatible version (such as major.minor.patch - or 1.0.32)]</version>
    <authors>[You]</authors>
    <owners>[You]</owners>
    <requireLicenseAcceptance>[true/false]</requireLicenseAcceptance>
    <description>[Description is actually required.]</description>
    <releaseNotes>[Link or something]</releaseNotes>
    <copyright>[Your copyright statement]</copyright>
    <tags>[Any tags you might have]</tags>
  </metadata>
  <files>
    <file src="bin\Release\net6\Obfuscated\*.dll" target="lib\net6" />
  </files>
</package>
</pre>

Pay close attention to the <files>-section – that’s where you specify which file or files you’ll include in the NuGet package you’re creating. In my case, I’m grabbing my obfuscated DLL (built with Release configuration) and drop it into lib\net6 (because it is built with .NET 6.0).

If you’re using something else than .NET 6.0 (like maybe .NET Framework, still), please adjust the values accordingly.

This file needs to be committed to Azure DevOps with your project. While it’s not (to my knowledge, anyway) a requirement to have the file named like the project, I’d consider it a good practice to name your nuspec file like this: “[yourprojectname].nuspec

How to package a DLL into a NuGet package using Azure DevOps?

Okay, so how’s this work in practice? Well, first you’ll need the nuspec file you just created earlier. Once you’ve committed that to Azure DevOps, configure a new build pipeline. You need a step for building, another one for packing, and finally a third one for pushing your package.

Below, you can see a simple example of such YAML build definition:

# ASP.NET
# Build and test ASP.NET projects.
# Add steps that publish symbols, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4

trigger:
- master

pool:
  vmImage: 'VS2017-Win2016'

variables:
  solution: '**/[yourprojectname].csproj'
  buildPlatform: 'AnyCPU'

steps:
- task: NuGetToolInstaller@1

- task: NuGetCommand@2
  inputs:
    restoreSolution: '$(solution)'
    packagesdirectory: '..\packages'

- task: VSBuild@1
  inputs:
    solution: '$(solution)'
    msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"'
    platform: '$(buildPlatform)'
    configuration: '$(buildConfiguration)'
    

- task: NuGetCommand@2
  inputs:
    command: pack
    packagesToPack: '**/[yourprojectname].csproj.nuspec'
    versioningScheme: byEnvVar
    versionEnvVar: PackageVersion
    packDestination: '$(Build.ArtifactStagingDirectory)\nugetpkg'

- task: NuGetCommand@2
  displayName: 'NuGet push'
  inputs:
    command: push
    publishVstsFeed: '[YourInternalAzureDevOpsNuGetFeed]'
    allowPackageConflicts: true

That’s it! Nice and simple, but figuring out the right way to go about it took a while.

References

mm
5 2 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments