NuGet
Two Easy Ways to Debug NuGet Packages and Edit Libraries
Debugging with Visual Studio has made coding so much simpler that developing without the same level of simple integrated debugging is practically unheard of. And yet that’s exactly what development with NuGet feels like. Debugging with NuGet is possible it’s just really crappy.
NuGet is great, especially if you want to break down monoliths and split functionality into libraries. However, developers are more likely to avoid using NuGet libraries or simply copy/paste common shared code than go through the tedious process of debugging NuGet packages.
A quick google search will show a range of complex solutions to this problem. In this article, I will show you two relatively simple solutions to integrated debugging: “munging” project files and using source & symbol serving.
Munging Project Files for Developing & Update Libraries
While there’s no great way to make integrated debugging & developing easy with NuGet packages, “munging” project files is the most straightforward solution.
Munging project files involves temporarily incorporating the code from the library project into the application you intend to debug. This solution is especially useful for situations where you want to write or edit the library code.
Munging project files can be done in a few simple steps. For this example, let’s say I need to debug/edit the Inedo.ExecutionEngine library, but I want to do so while using it in an application Otter.
Step 1: Uninstall the Packages Reference
In the Otter solution, Inedo.ExecutionEngine was installed in three different projects, so I right-clicked on my Solution, then Manage NuGet Packages, selected the library, and uninstalled it from the projects.

Step 2: Add Library Project
I right-clicked on my Solution, and selected Add Existing Project.

After adding the project to the solution, it will show up at the bottom like this:

Step 3: Add Project References
On each of the three projects, I uninstalled Inedo.ExecutionEngine project reference, I added a project reference to my newly added library project (Inedo.ExecutionEngine).

Step 4: Debug & Edit Code As Normal
And that’s that! Inedo.ExecutionEngine can just be debugged and edited like all other projects on my solution! Note that you won’t be able to commit source control changes to the munged library in the same instance of Visual Studio. But you can always commit your library changes later.
Step 5: Undo Project “Munging”
Once you’re done, make sure to undo the project “munging” to your library. Accidentally committing these changes will lead to broken builds and a headache for the rest of your team.

Project Munging with Tools & PowerShell
If you don’t do this very often, it’s not that big of a deal to click this many times. However, if the multiple steps and clicks are a little too bothersome there is a visual studio extension that can do some of the work, but it’s outdated and doesn’t work on newer project types.
It’s really simple to just write a very basic PowerShell script that uses the dotnet CLI.
# Munge-InedoLib.ps1
$pkgName = "Inedo.ExecutionEngine"
$pkgProjFile= "C:\Projects\Inedo.ExecutionEngine\Inedo.ExecutionEngine\Inedo.ExecutionEngine.csproj"
$slnFile = "C:\Projects\Otter\src\Otter.sln"
$projFilesToMunge = @( `
"C:\Projects\Otter\src\Otter.Service\Otter.Service.csproj", `
"C:\Projects\Otter\src\Otter.WebApplication\Otter.WebApplication.csproj", `
"C:\Projects\Otter\src\OtterCoreEx\OtterCoreEx.csproj" `
)
dotnet sln $slnFile add $pkgProjFile
foreach ($projFile in $projFilesToMunge) {
dotnet remove $projFile package $pkgName
dotnet add $projFile reference $libProjFile
}
Demystifying Symbols & Source Serving
While munging project files is great for writing & editing library code, symbols and source serving is more appropriate for debugging into library code. It can be difficult to wrap your head around all the various articles and documentation regarding symbols and source serving. The following sections aim to explain how everything fits together as clearly as possible.
What are Symbols?
Also known as PDB files, they essentially map compiled code (.dll and .exe files) to original source code files (.cs files). This is what visual studio uses behind the scenes for integrated debugging.
There are two types of symbol files: Microsoft PDB & Portable PDP.
- Microsoft PDB: These are an older format, and can optionally have instructions that point Visual Studio to download the mapped .cs files from a specialized Source Server. ProGet can act as a Source Server, and uses the .cs files you embed in the NuGet package to return the source code to visual studio.
- Portable PDB: These are a newer format, and work cross-platform (unlike Microsoft PDB). However, they do not support Source Server. Instead, you’ll need to use SourceLink to embed source file URLs in the NuGet package during compiling.
What are Symbol packages?
A symbol package is really just a NuGet package that contains symbol files. They can sometimes have different file extensions, like .symbols.nupkg or .snupkg.
Legacy Format (.symbols.nupkg)
.symbols.nupkg packages are considered to be legacy symbol packages, and can be created using the pack command on the nuget.exe client:
nuget.exe pack MyPackage.nuspec -Symbols
nuget.exe pack MyProject.csproj -Symbols
When created in this manner, a .symbols.nupkg file is mostly the same as the .nupukg file, but it includes .pdb files alongside the .dll files.
New Format (.snupkg)
.snupkg packages are the “new” format and can be created using by specifying the SymbolPackageFormat on either the nuget.exe CLI or the dotnet CLI.
nuget pack MyPackage.nuspec -Symbols -SymbolPackageFormat snupkg
nuget pack MyPackage.csproj -Symbols -SymbolPackageFormat snupkg
dotnet pack MyPackage.csproj -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg
When created in this manner, a .snupkg file will be just like the .nupukg file, but there will be .pdb files instead of the .dll files and the .nuspec manifest file will be slightly different.
Embedded Format (.nupkg)
Embedded Symbols packages are the most straightforward and recommended approach, especially with ProGet. They include the PDB and DLL inside a single NuGet Package instead of needing to use separate packages.
This involves setting the DebugType
property on your project file to embedded
.
<PropertyGroup>
<DebugType>embedded</DebugType>
</PropertyGroup>
By using the Embedded Format, this is the only change you need to make: you can simply push the package to ProGet, and you will be able to use ProGet’s symbol server.
What is a Source Server?
A source server enables a client to retrieve the exact version of the source files that were used to build an application.
The source code for a module can change between versions and over time, so it’s important to look at the source code as it existed when the version of the module in question was built. The source server retrieves the appropriate files from source control.
To use a source server, the application must have been source indexed. A NuGet feed in ProGet may be configured as a Symbol/Source server compatible with debuggers such as Visual Studio and WinDbg. The following is supported by the ProGet symbol server:
- Microsoft PDB format (C/C++, .NET)
- Source server
- Portable PDB format (.NET)
ProGet will index and serve portable PDB files as well as the traditional Microsoft PDB files, but portable PDB files need to use a build tool like Sourcelink.
What is SourceLink?
Sourcelink was created to enable anyone building NuGet libraries to provide source debugging for their users with little effort. Instead of embedding information in the PDB, it uses the package’s repository metadata element to locate code files in your web-based Git repository.
Using ProGet as a Symbol & Source Server
You can use a NuGet feed that you’ve already created in ProGet to server Symbols and source files.
Configuring your NuGet Feed ProGet
In order for ProGet to serve symbols for a particular NuGet feed, it must be configured to do so. From the ProGet home screen navigate to Feeds>Feed Name>Manage Feed Name>Symbol Server>Configure.
Ensure that the options under Symbol Server are correctly checked while noting the URL of the feed’s symbol server to be used within Visual Studio.

Configuring Visual Studio to work with ProGet
Enable Symbol Server Support
In order to debug into NuGet package libraries, Visual Studio must be configured to use ProGet as a symbol server.
To do this select Debug > Options, from the menu bar, then browse to Debugging > Symbols in the tree menu. Add the symbol server URL found on the Manage Feed page earlier, and specify a Symbol Cache Directory. By default, Visual Studio will use %LOCALAPPDATA%\Temp\SymbolCache
, but you may specify any path.

Enable Source Server Support
To configure source server support, browse to Debugging > General in the debugging options tree menu, and make sure the following settings are checked/unchecked as follows:
☐ Enable Just My Code
☑ Enable source server support
Additionally, you may have to uncheck:
☐ Enable .NET Framework Source Stepping
The settings should look like the following:

Stripping Symbols
If you want to use embedded symbol packages but prevent symbol files from being downloaded with your package, you can update the settings in ProGet. From the manage feed page, navigate to Symbol Server settings and select the “strip symbol files” option.

Debug NuGet Packages With ProGet
Debugging NuGet packages is anything but intuitive. Using the solutions outlined in this article will allow your developers to more easily integrate debugging with NuGet.
We recommend munging project files, but using embedded symbol packages is fine as well, especially if you’re debugging into library code. ProGet supports these solutions so your developers can debug NuGet packages as painlessly as possible.
Debugging is important, but there’s a lot more to learn about NuGet packages to successfully use them on the Enterprise level. Sign up for our mailing list to receive our upcoming guide that will guide you through everything NuGet!