Internet Explorer is no longer supported. Many things will still work, but your experience will be degraded and some things won't function. Please use a modern browser such as Edge, Chrome, or Firefox.

Symbol and Source Server

view on GitHub

Debugging in NuGet packages can be tedious, but you can make it easier by configuring your NuGet feeds to work as a Symbol/Source server compatible with debuggers like Visual Studio and WinDbg.

In this article, we'll walk through:

To learn more about the high-level concepts of NuGet package debugging, see our blog article Two Easy Ways to Debug NuGet Packages and Edit Libraries.

Creating Symbol Packages

There are two types of NuGet symbol packages: standard (.snupkg) and legacy (.symbols.nupkg). As of v2022.20, ProGet supports both package formats, but earlier versions support only the legacy format. See Symbol Package Formats for more information about these formats; in general, we recommend using standard symbol packages when possible.

Pushing Symbol Packages to ProGet

By default, when you use the nuget push command and there is a standard format (.snupkg) symbol package next to the main NuGet package, the symbol package is transferred by default.

If you are using a legacy NuGet symbol package, your main NuGet package will also be your symbol package. To ensure that you create a legacy symbol package so that it can be processed by ProGet, see Symbol Package Formats.

After configuring ProGet for symbol serving, you can push a package and its symbols to ProGet by simply adding the --source argument to dotnet nuget push with the feed's Endpoint URL.

For example:

dotnet nuget push kramericalib.4.1.2.nupkg  --source https://proget.kramerica.corp/nuget/internal-nuget/index.json

PDB Formats and Source Serving

ProGet can index and serve both .pdb file formats: portable and Windows (sometimes referred to as Microsoft PDB). Portable PDB files are cross-platform and an open specification, and are generated by default with modern .NET build systems. Portable PDB files have many advantages over the older format, but the main advantage for ProGet users is how they provide source files to debuggers.

Portable PDB files can use Source Link to embed source code repository information directly, allowing debugging environments like Visual Studio to request the exact version used to produce the .pdb file. Portable PDB files with Source Link are indexed and served by ProGet's symbol server. Once the debugger has downloaded the .pdb file, it will make any requests it needs to the source repository directly.

Source Server (Windows PDB)

Windows PDB files are a much older format and do not have a mechanism like Source Link to provide a direct link back to the source. Instead, these files contain a list of the full absolute paths of the source files used in the build process. Tools like pdbstr must be used to rewrite the .pdb file with paths that point to a specially formed URL instead.

When using the source server feature, ProGet performs this rewrite for each Windows PDB file in a NuGet package, provided that the package contains a src/ folder containing the source files used to build the package.

This system has a number of disadvantages:

  • The NuGet package itself must contain the source code used to build the package, which increases the size of the package and build complexity
  • PDB rewriting is an error-prone process that relies on very old and unmaintained tools and can be difficult to configure
  • The rewriting tooling requires ProGet to be running on Windows

For these reasons, we recommend using Portable PDB files whenever possible. ProGet accepts both types of files, but Portable PDB files provide much better support for source code debugging.

Configuring ProGet

To enable Symbol Server support for a NuGet feed, navigate to the Symbol Server tab on the Manage Feed page. This page also provides the URL that you can use to configure Visual Studio.

symbol-server-config.png

Clicking on the Configure Symbol Server button will present a few options for configuring the symbol server.

symbol-server-config-dialog.png

There are four Symbol Server modes for a NuGet feed:

  • Disabled: Symbol Server support for this feed is disabled.
  • Standard (.snupkg): Symbol Server is enabled, but only standard (.snupkg) format symbol packages are indexed.
  • Legacy: Symbol Server is enabled, but only legacy symbol packages are indexed. Standard (.snupkg) symbol files are not accepted.
  • Mixed: Symbol Server is enabled, and both standard and legacy symbol packages are indexed. If a package contains both legacy and standard symbols, only the standard symbols are used.

Legacy Symbol Server Options

When legacy or mixed mode is enabled, additional checkboxes are available to control legacy symbol package-specific options:

  • Strip symbol files: Legacy symbol packages store symbols directly in the "base" NuGet package. If you check this box, ProGet will remove these files from the package when the package is downloaded.
  • Strip source code: Removes everything in the 'src/' folder of a legacy symbol package when the package is downloaded.
  • Remove signature file: If the symbol or source code is removed from a package based on the previous two settings, the package's signature (if it has one) becomes invalid. Select this check box to also remove this signature in such cases.

Note that these settings have no effect on standard (.snupkg) files.

Verifying Indexed Symbols

When Symbol Server is enabled for a NuGet feed and a package has symbols indexed in ProGet, the Symbols tab is available on the package details page:

symbol-list.png

This page can be used to verify that ProGet has detected all of the symbols associated with the package, whether they are stored in the package itself (in the case of a legacy symbol package) or in a separate .snupkg file.

The Id and Age fields are used only to uniquely identify the PDB file by the debugger. Portable PDB files use a slightly different identifier scheme, so the Age field of these PDB files typically show as negative, but this is normal.

Configuring Visual Studio

Enable Symbol Server Support

To debug in NuGet package libraries, Visual Studio must be configured to use ProGet as the symbol server. Select Debug > Options... from the menu bar, then navigate to Debugging > Symbols from the tree menu. Add the symbol server URL you found earlier on the Manage Feed page and specify a Symbol Cache Directory. By default Visual Studio will use %LOCALAPPDATA%\Temp\SymbolCache, but you may specify any path.

enable-symbol-server.png

Enable Source Server Support

To configure source server support, go to Debugging > General in the debugging options tree menu and make sure the following settings are enabled/disabled 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:

debug-settings.png

Testing the Configuration

An easy way to test the configuration is to create a console application that consumes the NuGet package with symbols, write some throwaway code that you know will throw an exception, and then click the Start button in Visual Studio to begin debugging:
code1.png

If everything is configured correctly, Visual Studio tries to load the symbols locally, then queries the ProGet symbol server if they cannot be found, and the exact line that throws the exception is highlighted:
code2.png

Troubleshooting

In some cases, the symbol server fails for various reasons, the most common being misconfiguration. To display the PDBs that Visual Studio has loaded, select the Debug > Windows > Modules menu option during debugging and locate the desired DLL in the list. The symbol status is displayed, along with the version and path to the DLL and the downloaded symbols.

modules.png

Whether or not the symbols have been loaded, you can right-click on the DLL and select "Symbol Load Information..." to view the diagnostic messages associated with the symbol server for that library.

symbol-load-info.png

The hex string in the file path should also start with the GUID listed in ProGet:

hex.png

The GUID will be found under the "Symbols" tab on the NuGet package.

Common Errors

The most common errors (based on previous support inquiries) include:

  • Using the wrong URL, e.g. http://«proget-server»/nuget/«feed-name» instead of the correct http://«proget-server»/symbols/«feed-name»
  • Pushing both NuGet packages (with and without symbols) when using legacy symbol packages
  • Trying to consume symbols for connector packages (which is not supported, a workaround is to pull packages locally or use a separate feed for symbols)
  • Not including source files under the /src/ directory at the root of the .nupkg file (legacy symbol packages only)