Source Link is a Microsoft technology that lets .NET developers debug the source code of NuGet packages referenced by their applications. I underlined source code because at debugging time the user doesn’t just get C# code decompiled from the IL code within referenced assemblies. Instead the developer debugs the original C# source code used to build the libraries, with original comments and formatting available.
Source Link is language, IDE and source-control agnostic. Source Link can be used from debugging sessions done through Visual Studio, VS Code or Rider IDE.
Debugging with Source Link in Visual Studio
The Newtonsoft.Json package supports Source Link. It means that when debugging the program below, one can step into the SerializeObject()
method original source code.
1 2 3 4 5 6 7 8 9 |
var person = new Person { FirstName = "Albert", LastName = "Einstein ", YearOfBirth = 1879 }; string json = Newtonsoft.Json.JsonConvert.SerializeObject(person); Console.WriteLine(json); public class Person { public string FirstName { get; init; } public string LastName { get; init; } public int YearOfBirth { get; init; } } |
Prior doing so a few settings must be setup in Visual Studio:
- Enable: Tools > Options > Debugging > Symbols > NuGet.org Symbol Server
- In Tools > Options > Debugging > General
- Disable: Enable Just My Code
- Enable: Enable source server support and Enable Source Link support
Then start debugging the program (F5). Before starting the debugging session, it takes a few seconds to load symbols for packages referenced:
You can now Step-Into Newtonsoft original sources:
The file JsonSerializer.cs
has been downloaded from GitHub and stored in the folder C:\Users\usr\AppData\Local\SourceServer\634989e5314d385c82c8a3269e286aacd49e4527b9c315d6bd38afcf4ee504e3\Src\Newtonsoft.Json
.
How Source Link works?
If you download the Newtonsoft.Json package from NuGet and unzip its content, you’ll notice a generated file in it named Newtonsoft.Json.nuspec
. This file contains a <repository>
tag that points to both the location and commit hash for these bits:
1 |
<repository type="git" url="https://github.com/JamesNK/Newtonsoft.Json" commit="0a2e291c0d9c0c7675d445703e51750363a549ef" /> |
In this scenario the package zipped doesn’t contain any PDB file. At debug time, this location and commit hash are used to fetch the source files and the PDB files from GitHub that are then stored locally in a \Temp\SymbolCache
directory.
Enabling Source Link for your own Packages
Enabling Source Link for your own packages makes the life of the developers that use it much easier.
At the minimum a <PublishRepositoryUrlsproj>
tag and a reference to a source link package must be added to your .csproj
project file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <!-- Insert the tag <repositoy .../> in the .nuspec file --> <PublishRepositoryUrl>true</PublishRepositoryUrl> </PropertyGroup> <ItemGroup> <!-- Reference this package to enable SourceLink used with the source control GitHub --> <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> </ItemGroup> </Project> |
If you use GitLab or Bitbucket you could instead reference the Microsoft.SourceLink.GitLab or Microsoft.SourceLink.Bitbucket.Git package.
Embedding the PDB files
Some optional tags let’s embed the PDB files inside the main .nupkg package or in a side package with extension .snupkg. The first option is not recommended as it increases the size of the main package and thus increases the restore time, even for scenarios where symbols are not required.
1 2 3 4 5 6 7 8 9 10 11 12 |
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> ... <!-- Embed symbol files (*.pdb) in the .nupkg package --> <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder> <!-- or embed symbol package in a symbol package (.snupkg) --> <IncludeSymbols>true</IncludeSymbols> <SymbolPackageFormat>snupkg</SymbolPackageFormat> </PropertyGroup> ... |
NuGet.org hosts its own symbols server repository that works with .snupkg symbol side packages. In the first section of the present article, when we checked Tools > Options > Debugging > Symbols > NuGet.org Symbol Server we told Visual Studio to fetch symbol from the NuGet.org symbols server repository.
Embedding sources in the PDB file
Finally you can decide to optionally embed source files within the PDB files with these options:
1 2 3 4 5 6 7 8 9 10 11 12 |
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> ... <!-- Embed all project source files into the generated PDB --> <EmbedAllSources>true</EmbedAllSources> <!-- Embed project source files that are not tracked by the source control or imported from a source package to the generated PDB. Has no effect if EmbedAllSources is true. --> <EmbedUntrackedSources>true</EmbedUntrackedSources> </PropertyGroup> ... |
Conclusion
With Source Link, the debugging process becomes smoother, more intuitive, and insightful, leading to accelerated development cycles With its seamless integration into the NuGet ecosystem, Source Link empowers developers to delve deep into the inner workings of their references, enabling them to troubleshoot and resolve issues with unprecedented efficiency.