Publish a self-contained .NET app on Azure DevOps
I had a problem today that I ended up spending quite some time resolving. We have some internal CLI's that we have been migrating to .NET Core lately. Rather than having to clone the code and build it when needed, I wanted to set up an automated build, producing a self-contained console app on our Azure DevOps server.
When setting up builds on Azure DevOps, I pretty much follow the same pattern over and over again. The first step is usually setting up a dotnet restore
task:
Notice the custom feed selected in the Feeds to use section. The reason I'm mentioning this is that it will cause problems in a minute.
Next, I add a dotnet build
step:
So far so good. To produce a self-containing output, you can use dotnet publish
together with the --runtime
option. In my case I want to produce a self-containing program for 64 bit Windows, why the command looks like this:
dotnet publish --runtime win-x64
Adding that command as a build step is easy:
Unfortunately, the build failed on Azure DevOps with the following error:
error NETSDK1047: Assets file '...\obj\project.assets.json' doesn't have a target for '.NETCoreApp,Version=v5.0/win-x64'. Ensure that restore has run and that you have included 'net5.0' in the TargetFrameworks for your project. You may also need to include 'win-x64' in your project's RuntimeIdentifiers.
When looking through my csproj
file, the project doesn't include a runtime as proposed by the error message:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
To fix the error, I simply add a RuntimeIdentifiers
element:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
</PropertyGroup>
This fixed the build error just to reveal a new error in the dotnet publish
step:
C:\Program Files\dotnet\sdk\5.0.301\NuGet.targets(123,5): error : Unable to load the service index for source .../_packaging/Elmah.Io.Shared/nuget/v3/index.json.
C:\Program Files\dotnet\sdk\5.0.301\NuGet.targets(123,5): error : Response status code does not indicate success: 401 (Unauthorized).
Remember the dotnet restore
step which pointed out a custom NuGet feed to (also) restore packages from? Unfortunately, neither build
or publish
has this option, why I need to disable restore on those steps (no need to restore and build multiple times anyway). This can be done by modifying the build step:
dotnet build --runtime win-x64 --no-restore
This tells the build command to build for the win-x64
runtime and don't do NuGet restore. We need the runtime parameter since dotnet publish
will no longer restore and build if required. The --no-restore
parameter instructs build not to restore NuGet packages.
Similar, I extended the publish command:
dotnet publish --runtime win-x64 --no-build mycli.csproj
By including the --no-build
parameter, neither restore or build is executed as part of this step.
The changes produce a nice self-contained .NET 5 console app. The final step is to publish the generated zip-file using a Publish build artifacts step:
When anyone needs the newest build of the CLI, he/she can download it by navigating to the most recent build and clicking the Artifacts button: