Skip to content

MS_NuGetPackageDebugging

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

NuGetパッケージのデバッグ

概要

  • 紆余曲折が多くなったため一旦クリア。
  • 参考の情報を参照すれば対応可能。

補足(「紆余曲折」の中身): 原文が整理を諦めるほど、
この分野は方式が何度も入れ替わった。経緯を押さえておくと読みやすい。

① *.symbols.nupkg(レガシ シンボル パッケージ)
      + SymbolSource.org / ソース サーバー(srcsrv)
      → pdb にソースの取得先を埋め込む方式。運用が煩雑
           ↓
② *.snupkg(新しいシンボル パッケージ形式・2018〜)
      + NuGet.org シンボル サーバー
      → シンボルは NuGet が配る
           ↓
③ Source Link
      → ソースは Git ホスティング(GitHub 等)から直接取る
      → 現在はこれが本命

要点: 「シンボル(pdb)」と「ソース(.cs)」は
別々に配られる。この 2 つを混同すると理解が難しくなる。

必要なもの 何が解決するか 現在の手段
シンボル(pdb) 行番号、変数名、スタック トレース .snupkg、または pdb 同梱
ソース(.cs) ステップ実行して中身を読む Source Link

詳細

NuGet サーバー

nuget pack

  • 基本的に、nuspec ファイルは 1 つだけ作成して、
  • -Symbols -SymbolPackageFormat snupkg オプションで nuget pack すれば良い。

nuget push

  • *.nupkg ファイルと *.snupkg ファイルが生成される。

    • *.nupkg ファイル:*.dll*.xml が格納される。
    • *.snupkg ファイル:*.pdb が格納される。
  • .nupkg.snupkg の両方が在る状態で nuget push すれば両方が公開される。

補足(SDK スタイルでの書き方): 原文は nuget.exe 前提だが、
SDK スタイル プロジェクトでは .csproj に書くのが定石である。

<PropertyGroup>
  <!-- シンボル パッケージ(.snupkg)も作る -->
  <IncludeSymbols>true</IncludeSymbols>
  <SymbolPackageFormat>snupkg</SymbolPackageFormat>

  <!-- ポータブル PDB(クロスプラットフォーム。既定) -->
  <DebugType>portable</DebugType>

  <!-- Source Link(後述)とセットで指定する -->
  <PublishRepositoryUrl>true</PublishRepositoryUrl>
  <EmbedUntrackedSources>true</EmbedUntrackedSources>
  <ContinuousIntegrationBuild
      Condition="'$(TF_BUILD)'=='true' or '$(GITHUB_ACTIONS)'=='true'">true</ContinuousIntegrationBuild>
</PropertyGroup>
dotnet pack -c Release
dotnet nuget push bin/Release/*.nupkg -s https://api.nuget.org/v3/index.json -k $KEY
# .snupkg は .nupkg と同じディレクトリにあれば自動で一緒に push される

.snupkg に入るのはポータブル PDB のみである
(Windows 専用の従来型 PDB は受け付けられない)。
DebugTypefull にしていると弾かれるため、
portable にする必要がある。

デバッグ・サーバー

シンボル・サーバー

NuGet シンボル・サーバーを有効にするだけで良い。
https://symbols.nuget.org/download/symbols

補足(設定場所): Visual Studio の
**[ツール]→[オプション]→[デバッグ]→[シンボル]**で、
上記 URL を追加する(「NuGet.org シンボル サーバー」の
チェック ボックスが用意されていることもある)。

併せて、[全般]の設定も確認する。

設定 意味
マイ コードのみを有効にする オフ 外部コードに入れるようにする
ソース サーバー サポートを有効にする オン 旧方式のソース取得
ソース リンク サポートを有効にする オン Source Link を使う
元のバージョンと完全に一致するソース ファイルを要求する オフ ハッシュ不一致でも開く

ソース・サーバー

  • NuGet サーバーでのサポートがなくなり、ソース・リンク(詳細不明)に
    置き換わっている模様。
  • ちなみに、nuget pack でのソース同梱もできなくなっている
    (contents では js/css 的になってしまう)。

補足(Source Link とは/原文の「詳細不明」を補う): Source Link は、
PDB の中に「このソースはどこの Git リポジトリの、どのコミットか」を
埋め込む
仕組みである。

【従来(ソース サーバー / srcsrv)】
   pdb に「ソース取得コマンド」を埋め込む
     → 取得先ごとに独自実装。SymbolSource.org 依存

【Source Link】
   pdb に「リポジトリ URL + コミット SHA + ファイルパス」を埋め込む
     → デバッガが raw.githubusercontent.com 等から直接取得
     → GitHub / GitLab / Azure Repos / Bitbucket に対応

利点:

  • 公開リポジトリなら、利用者が何も準備せずステップ実行できる
  • コミット単位で一致するソースが取れる(版ずれが起きない)
  • ソースをパッケージに同梱しなくてよい(サイズが増えない)

設定(.NET 8 以降は SDK に組み込まれ、追加パッケージ不要):

<PropertyGroup>
  <PublishRepositoryUrl>true</PublishRepositoryUrl>
  <EmbedUntrackedSources>true</EmbedUntrackedSources>
  <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>

<!-- .NET 7 以前は、ホスティング先に応じたパッケージを追加する -->
<ItemGroup>
  <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0"
                    PrivateAssets="all" />
</ItemGroup>

ContinuousIntegrationBuild=true が重要で、
これがソース パスを**決定的(deterministic)**にする
ビルド環境と開発環境のソースファイルパスを一致させる(PDB)。)。

なお、非公開リポジトリの場合は Source Link だけでは足りない
(利用者がリポジトリにアクセスできない)。
その場合は EmbedAllSources でソースを PDB に埋め込む選択肢がある。

<EmbedAllSources>true</EmbedAllSources>   <!-- pdb が大きくなる点に注意 -->

最新の検証結果

.NET Framework

シンボルサーバーで上手く動作しない。

  • SymbolCache には、.NET Framework の pdb のみが落ちてきているが、上手く動作しない。
  • NuGet が取得した DLL と SymbolCache の pdb をセットにして参照設定すれば上手く動作する。

.NET Core

シンボルサーバーで上手く動作する。

補足(.NET Framework で動かない理由): 原文の観測は妥当で、
原因は PDB の形式の違いにある。

従来型 PDB (full) ポータブル PDB (portable)
対応 Windows 専用 クロスプラットフォーム
既定 .NET Framework の既定 .NET Core / .NET の既定
.snupkg 受け付けられない これのみ
Source Link 限定的 完全に対応

つまり、

.NET Framework プロジェクト(DebugType=full のまま)
   → .snupkg を作れない/シンボル サーバーと噛み合わない

.NET Framework でも DebugType を portable にすれば動く

対処: .csproj に明示する。

<PropertyGroup>
  <DebugType>portable</DebugType>
</PropertyGroup>

ただし、古い packages.config 形式のプロジェクトでは
設定が効かない場合がある
ため、
原文の回避策(DLL と PDB を手で揃えて参照設定する)が
現実的な落としどころになることもある。

より確実な代替として、PDB をパッケージに同梱する方法もある。

<!-- .snupkg を使わず、nupkg に pdb を入れてしまう -->
<AllowedOutputExtensionsInPackageBuildOutputFolder>
  $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
</AllowedOutputExtensionsInPackageBuildOutputFolder>

パッケージ サイズは増えるが、
シンボル サーバーの設定が要らないため、
社内配布(NuGetプライベート・リポジトリ)では
こちらの方が扱いやすい場合が多い。

補足(デバッグできないときの切り分け手順): 症状から原因を絞る。

① そもそもブレークポイントが「シンボルが読み込まれていません」
      → PDB が無い/版が一致しない
      → 「モジュール」ウィンドウでシンボルの状態を確認

② 行番号は出るが、ソースが開かない
      → PDB はある。ソースが取れていない
      → Source Link を確認(オプションで有効か/URL にアクセスできるか)

③ ソースは開くが、行がずれる/変数が見えない
      → Release ビルドの最適化
      → 「マイ コードのみ」をオフ、[抑制] JIT 最適化を無効化

④ 外部コードに入れない
      → 「マイ コードのみを有効にする」がオン

**[デバッグ]→[ウィンドウ]→[モジュール]**が最も有用で、
各 DLL について「シンボルの状態」「読み込み元」「PDB のパス」を
一覧で確認できる。

参考

Microsoft Learn

その他

デバッグ可能なNuGetパッケージのサンプル


Tags: 移行, .NET開発, デプロイ, デバッグ, NuGet

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally