Back to all posts

.NET 5 Deterministic Builds & Source Linking

Posted on Feb 15, 2021

Posted in category:
Development
.NET

I have been working recently on a number of improvements to our collection of .NET Utilities. One of these tasks was updating projects to support deterministic builds as well as Source Linking to provide a better developer experience. I utilized NuGet Package Explorer to validate the changes once complete.

Why Do It?

Before I get into the specifics, I wanted to share WHY we must do this for items we publish. By default, each time you build a project, you will get a slightly different DLL file due to the internal metadata; this makes it hard to validate if a particular version of a project/file is what it says it is.

By making a build deterministic with the same inputs, we will get the same output, and this allows for the integrity of an assembly to be validated. For example, to determine if someone modified the source and created a custom build.

Source Linking is all about providing a great experience for your end-users by allowing better debugging experiences. Microsoft uses this technology for all of .NET Core and other aspects and strongly encourages others to use the technology as well.

Setting It Up

The process of setting things up is pretty easy, just a few steps.

Add Source Link NuGet

The first step is to add the proper SourceLink NuGet package to your environment. You can view all available packages from the SoureLink repository; however, a few important ones.</p.

  • Microsoft.SourceLink.GitHub - For those in GitHub based repos
  • Microsoft.SourceLink.AzureRepos.Git - For those in Git repositories on Azure DevOps

These packages contain the magic that is aware of your repository type and can determine the information necessary for tracked/untracked files, commit-history, and source location, taking all work away from you.

Set Continuous Integration Flag

We need to add a new property group ONLY when being built in the CI environment. We can use a condition to handle this, examples for Azure DevOps & GitHub Actions:

Azure DevOps
<PropertyGroup Condition="'$(TF_BUILD)' == 'true'">
    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
GitHub Actions
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup> 

This simply ensures that the environment knows this was a build from a CI system.

Final SourceLink Setup

The final piece of setup is to configure how we want to set up our project. These elements need to also be added inside of your .csproj file and can be added to any existing property group.

SourceLink Setup
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<EmbedUntrackedSources>true</EmbedUntrackedSources> 

In this example, I have published a high level of detail as this is our open-source project. A bit of detail on these options.

Setting Purposes
PublishRepositoryUrl If selected, this will publish the repository URL and the commit. This should NOT be set if you do not intend to make the repository known.
IncludeSymbols This controls if symbol files are included in the process
SymbolPackageFormat The format of packaging, by setting this to snupkg a separate package is created which can be published to NuGet
EmbedUnTrackedSources When set to true items that participated in the compile, but not included in source control will still be included. Helpful for items such as assembly info, etc.

Now, if you build your package the proper source linking should be completed and if creating NuGet packages you should pass all validations in NuGet Package Explorer. Those using your packages have the ability to experience much better debugging.

Happy Coding!