69
votes

I have put a library that my team uses into a nuget package that is deployed from TeamCity into a network folder. I cannot debug into this code though! SymbolSource is one solution I have read about but I would much rather find some way to have access to the .pdb/source files directly from TeamCity. Does anyone know how to do this?

Edit. When I check 'Include Symbols and Source' in the Nuget Pack build step, TeamCity creates a .Symbol.nupkg in addition to the .nupkg file in the network folder. The .Symbol.nupkg contains the src and the .pdb file.

Edit. I unchecked 'Include Symbols and Source' on TeamCity and added the following to my nuspec file:

  <files>
    <file src="..\MyLibrary\bin\release\MyLibrary.dll" target="lib\net40" />
    <file src="..\MyLibrary\bin\release\MyLibrary.pdb" target="lib\net40" />
    <file src="..\MyLibrary\*.cs" target="src" />
    <file src="..\MyLibrary\**\*.cs" target="src" />
  </files>

This added the dll, the pdb, and the source files for my library in the nuget package and didn't generate a .Symbols file which I think is only needed for symbol servers.

10

10 Answers

74
votes

Traditional method

  1. Put the pdb in the NuGet package alongside the dll.
  2. Add the source code to the Debug Source Files for the solution that references the package.

This means you'll be able to step through code and view exceptions, but you might have to find a file on disk and open it before you can set a breakpoint. Obviously you need to be careful that the source is at the right revision.

More detail on step

If you're currently packaging without a Nuspec, you'll need to create a Nuspec, then add the pdb to the list of files in the lib folder "NuGet spec" may be a useful command for generating the initial spec as defined in NuGet docs. Then ensure the Team City Nuget Pack step is referencing your new nuspec.

More detail on step 2

When you have a solution open, right click on Solution, select Properties...Common Properties...Debug Source Files, and add the root source directory for the relevant binary reference. Or see MSDN. Note, you can't open the solution properties while debugging.

Still not hitting breakpoints?

Try disabling this from Tools->Options: Disable exact source match


Modern way for public or private repos

To ensure the exact version of the source is available, embed it at build time.

From Visual Studio 2017 15.5+ you can add the EmbedAllSources property:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <EmbedAllSources>true</EmbedAllSources>

Modern way for public repos

To keep your nuget and library size small, you can use the sourcelink package.

It generates a pdb that directs the debugger to the correct version of the file from your VCS provider (e.g. GitHub, BitBucket).

29
votes

The latest version of dotPeek (free!) can act as a symbol server and generate pdb files on the fly. This has allowed me to debug into the dlls that are served via teamcity.

Download it here:

http://blog.jetbrains.com/dotnet/2014/04/09/introducing-dotpeek-1-2-early-access-program/

Instructions on how to set it up here.

https://web.archive.org/web/20160220163146/http://confluence.jetbrains.com/display/NETCOM/dotPeek+Symbol+Server+and+PDB+Generation

8
votes

You could of course set-up & configure your own symbol server, but it's probably easiest to...

  1. download and install Inedo's ProGet
  2. enable symbol serving on the target feed
  3. publish packages from TeamCity to the ProGet feed
  4. use ProGet as your primary feed source (as it can aggregate multiple feeds including nuget.org)

All of this can be done with the free edition of ProGet.


disclaimer -- my day job is at Inedo

6
votes

In your .nuspec (directly under <package>):

<files>
  <file src="bin\$configuration$\$id$.pdb" target="lib\net451\" />
</files>

(change net451 to the platform you're compiling for)

3
votes

I've found a super simple way to do this, which I have blogged about here:

https://mattfrear.com/2017/11/29/speed-up-development-in-a-nuget-package-centric-solution/

This only works if you're using the new .NET Core style .csproj with <PackageReference> (on either .NET Core or .NET Framework).

This again assumes you have access to the source code of the NuGet package.

  1. Build and compile the NuGet package on your local machine
  2. Copy the .dll you've just compiled into your local NuGet packages feed folder (On my machine, this is C:\Users\matt\.nuget\packages\), overwriting the existing NuGet package .dll.

That's it! You should be able to step into the package while debugging. No messing around with .pdbs or source servers. This has greatly sped up my development cycle.

2
votes

Since this question was originally posted, Jetbrains have written an entire blog post on how to accomplish this. The steps can be summarised as:

  • Install Debugging Tools for Windows on the agents.
  • Install & Enable the Symbol Server plugin.
  • Add Symbol Files Indexer build feature to your build configurations.
  • Ensure PDB files are output as an artefact.
  • Configure Visual Studio to use TeamCity as source server.

If you are using Nuget Package build steps, you can check 'Include Symbols and Source' to output a .symbol.nupkg which contains the PDBs. Depending on whether the Symbol Files Indexer is smart enough to look inside this file or not, you may need to change the file extension for things to work.

The full details are given here: https://blog.jetbrains.com/teamcity/2015/02/setting-up-teamcity-as-symbol-and-source-server/

2
votes

This is what I have found to work, but all the steps are probably not required...

Note: this doesn't allow you to debug both, only either the nuget package or the solution in which it is installed.

  1. Run Visual Studio as Administrator
  2. Open and Start the host application (the one in which you installed the Nuget package) without debugging (Ctrl + F5)
  3. In the Nuget package solution, ensure that Tools > Options > Debugging > General > "Require source files to exactly match the original version" is NOT checked.
  4. Ensure that "Enable just my code" is NOT checked
  5. Add a new folder in Tools > Options > Debugging > Symbols pointing to the source directory of the Nuget package. (You literally enter the folder path , see image below)
  6. Click Debug > Attach to Process...
  7. Find iisexpress (there may be multiple, it won't do any harm attaching to all)

Screenshot of Symbol Source Locations

2
votes

If you have the source code for the package, then the foolproof (but possibly laborious) method is:

  1. Add the source code for the package to your solution (right click Solution -> Add Existing Project)
  2. Go through all of your projects in the solution and remove the NuGet reference to the library (i.e. open the References folder under each project and delete the reference to the package.) Then, add a reference to the NuGet package project in your solution. (i.e. Right click References, add Reference, choose Projects and tick the box for the project)

I had to do it this way when I the method I wanted to debug inside the NuGet package was called by the framework and not by my code, thus I couldn't step into it. (In my case, the method was an ASP.NET DelegatingHandler).

Once you're done you'll want to undo all your changes via source control so that the NuGet package is referenced correctly.

0
votes

If your code is in a public Git repository, or, at least in your network, is accessible without authentication, then GitLink would be an option:

https://github.com/GitTools/GitLink

GitLink makes symbol servers obsolete by changing the PDB to point to the Git server. But, as said before, this makes it necessary for the Git repository to be public - until now there's no "proper" way to authenticate when accessing a private repository.

0
votes

Microsoft has now integrated the SourceLink NuGet package at https://github.com/dotnet/sourcelink/ which allows source code to be downloaded on demand while debugging if the publisher of the NuGet package sets it up.