71

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.

Pang
  • 9,564
  • 146
  • 81
  • 122
anthonybell
  • 5,790
  • 7
  • 42
  • 60

10 Answers10

73

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).

Graham
  • 1,529
  • 16
  • 22
  • 9
    Not sure if it is a bug but anyone trying this in VS2015 clicking "Debug Source Files" doesn't show the correct window, it seems to show the configuration manager. – Choco Smith Oct 06 '15 at 08:34
  • @Choco Smith I have the same problem. Right click on solution file and Common Properties->Debug Source Files show Configuration Manager Window in VS 2015. Do you know how show Debug Source Files window in VS2015? – honzakuzel1989 Jan 12 '16 at 08:03
  • Has always worked fine for me in VS2015. I used this today on VS Enterprise 2015, version 14.0.24720.00. If it's not just a rogue extension messing up your menus, perhaps create a Microsoft Connect issue? https://connect.microsoft.com/VisualStudio/MSNetNative – Graham Jan 13 '16 at 16:28
31

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

Henrik Stenbæk
  • 3,982
  • 5
  • 31
  • 33
anthonybell
  • 5,790
  • 7
  • 42
  • 60
8

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

Karl Harnagy
  • 717
  • 5
  • 10
  • Why do I need a 'symbol server' If I already have the .Symbol.nupkg file? Can't Visual Studio just read this file directly? – anthonybell Feb 18 '14 at 21:48
  • 1
    @anthonybell oh most definitely not! A ".symbol.nupkg" file is nothing more than a zip file. Visual Studio needs to first find a remote .pdb file (by assembly hash), and that file will then point to a hashed source file url. A symbol server like ProGet will reindex the pdb file and serve files based on that. See http://inedo.com/support/kb/1036/using-progets-symbol-server – Karl Harnagy Feb 19 '14 at 02:16
  • @anthonybell according to [MS documenation](https://learn.microsoft.com/en-us/windows/desktop/dxtecharts/debugging-with-symbols) this should be possible but so far VS fails to load symbol packages from either network shares or local folders. – Markus L Aug 28 '18 at 13:18
  • I had to modify the "Symbol Server" settings for my feed and disable the setting "Strip symbol files from packages downloaded from this feed". But uninstalling and then re-installing the package still didn't include the *\*.pdb* file in the package. – Kenny Evitt Dec 13 '18 at 16:21
  • Restarting ProGet didn't help either, but I'm running an old version of Visual Studio (2012) and ProGet (3.8.6). – Kenny Evitt Dec 13 '18 at 16:35
  • In the end, I had to download the 'with symbols' NuGet package file from ProGet and then install it in my other project from the NuGet Package Manager Console with the download directory as the `Source` argument value. – Kenny Evitt Dec 13 '18 at 18:04
6

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)

Pang
  • 9,564
  • 146
  • 81
  • 122
3

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.

Matt Frear
  • 52,283
  • 12
  • 78
  • 86
  • the above options regarding symbol servers are better. This method is error prone and time consuming to do every time. Setting up a symbol server is a one time setup – hofnarwillie Jul 12 '16 at 15:37
  • @hofnarwillie Is it possible to set a breakpoint inside the source code of the NuGet package if you're using a symbol server? Or are you only able to set a breakpoint in your own code and then step into the NuGet package's source code? – Matt Frear Jul 20 '16 at 12:37
  • You can do both, however, I actually found that you don't even need to run a symbol server (but in this case you can only debug one at a time). See my answer for more details. http://stackoverflow.com/a/38578379/883644 – hofnarwillie Jul 25 '16 at 22:30
  • 1
    Thanks for that. Although my downvoted answer is laborious, I stand by it as it allows me to debug both my code and the NuGet package without a source server – Matt Frear Jul 27 '16 at 12:16
  • 3
    I wouldn't like anyone in my team to do it because it is error prone and time consuming. Down voting because I think that it is not the right way to approach it. I'm sure if enough people agree with you that it is a sensible way to do it then they will up vote it and I will be thoroughly corrected. – hofnarwillie Jul 28 '16 at 10:32
  • 1
    If you have the source code, you can also do like this: In the project properties of the project where a nuget package is used add the bin\debug folder of the private nuget package source code to the reference path. (see http://www.mariuszrokita.com/how-to-debug-step-into-a-class-library-referenced-as-nuget-package/) – MBWise Mar 30 '17 at 15:42
  • I have a symbol server and PDB debug packages but I can't seem to find a way to place a breakpoint in the PDB code. I can't trace into the code since it is injected and it runs in a separate thread (WinForms UI). No matter what I have tried none of this works. This is the only option I have left. – Jeremy Jul 26 '17 at 17:25
  • @MBWise Link is dead, use http://web.archive.org/web/20161207151745/http://www.mariuszrokita.com/how-to-debug-step-into-a-class-library-referenced-as-nuget-package/ – Ian Kemp Aug 16 '17 at 14:30
  • 1
    Upvoting because it doesn't require buying/installing some random product or server, or changing the nuspec, which you might not always want for a quick look at something. Just use source control properly to undo your changes. `git co .`. Done – Craig Brett Nov 14 '17 at 11:35
3

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.

Matt Frear
  • 52,283
  • 12
  • 78
  • 86
  • This only works with the new project file format / ProjectReferences – weir Jan 09 '18 at 19:18
  • Your example location is the default global‑packages location on Windows (%userprofile%\.nuget\packages). The path from there to the dll in NuGet 3.3+ is packagename\version\lib\. Is that where you are copying it? Are you manually copying or using nuget add? – jla May 09 '18 at 23:48
  • @jla yes, you should see the existing dll, either copy over that or I rename the original one in case you want to restore it. – Matt Frear May 11 '18 at 08:27
2

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/

Jack Ukleja
  • 13,061
  • 11
  • 72
  • 113
2

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

hofnarwillie
  • 3,563
  • 10
  • 49
  • 73
  • @CristianE. The nuget package can be a class library. The instructions above are for exactly that. It would still need to be executed in a host application like a website or console app in which you install the nuget package. – hofnarwillie Sep 15 '17 at 14:11
0

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.

BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
0

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.

NYCdotNet
  • 4,500
  • 1
  • 25
  • 27