Under the hood with debugging in Blazor WebAssembly (Blazor wasm デバッグ内部のお話し)【訳】

本記事は [Blazor Advent Calendar 2020](https://qiita.com/advent-calendar/2020/blazor) 21 日目の投稿です。

今回は最近 Blazor WebAssembly のデバッグ時の動作に関して調べているときに、ふと出会った Blazor wasm の開発者の方の良記事がありましたので、せっかくなのでこの機会にその英語 Blog を日本語訳にてご紹介します！


# はじめに
今回は Blazor WebAssembly の開発に携わる Safia Abdalla さんの Blazor WebAssembly のデバッグの仕組みの概要を紹介しているブログ記事 [Under the hood with debugging in Blazor WebAssembly](https://safia.rocks/blog/blazor-wasm-debugging/) を【日本語訳】してみました。

翻訳にあたり、元記事の Safia さんに事前に許可はいただいております。快諾いただき大変感謝しております。ちなみに Safia さんは先日の .NET Conf 2020 の [A talk for trailblazers: Blazor in .NET 5](https://www.youtube.com/watch?v=Nag6u5TxjIA) のセッションにも出演していた方です。

なお、本記事はデバッグの具体的な方法というより、Chromium ベースのブラウザにおける Blazor WebAssembly のデバッグ時の大枠の仕組み的な部分の解説資料です。デバッグの手順を知りたい方は [ASP.NET Core Blazor WebAssembly をデバッグする](https://docs.microsoft.com/ja-jp/aspnet/core/blazor/debug?view=aspnetcore-5.0&tabs=visual-studio) をご参照ください！

では、早速記事の紹介をはじめましょう！以下、日本語訳です。


# Under the hood with debugging in Blazor WebAssembly

Blazor に馴染みある方はご存じかと思いますが、Blazor には 2 つの異なるホスティングモデルがあります。

- Blazor WebAssembly：ブラウザ内で WebAssembly (wasm) で記述した .NET ランタイム上で Blazor が実行される
- Blazor Server ：サーバーのマシン上の .NET ランタイムで Blazor が実行される

Blazor Server アプリケーションをデバッグする際は、標準の .NET Debugger を利用しデバッグします。しかし、Blazor WebAssembly はブラウザ上で実行されているため、Blazor Server と同様のデバッグ方法は適用できません。Blazor WebAssembly でも同じデバッグ エクスペリエンスを実現するため、興味深いさまざまなテクノロジーの組み合わせが登場していることが分かっています。


## The Chrome DevTools Protocol (CDP)
CLI を利用し新しい Blazor WebAssembly アプリケーションを作成したとしましょう。

```
$ dotnet new blazorwasm -o DebuggingTest
$ cd DebuggingTest
$ dotnet run
```

ブラウザ内でデバッグを開始するために、"Alt + Shift + D" を使用します。この時点で、`--remote-debugging` 引数付きで Chromium ブラウザを新たに開くように指示されていることでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150728/5bbb86d6-94fd-46dc-39c1-58d8a12d6a1b.png)

このアラートは、我々がカバーする最初の重要なポイントの1つである Chrome DevTools Protocol を示してます。Chrome DevTools は、Chromium を利用しているブラウザに含まれているクライアント側のインターフェースであり、開発者が elements を検査したり、Webアプリに関連付けられたソースファイルを参照したり、アプリケーションをデバッグすることを可能にします。DevTools は、Chrome DevTools Protocol (Chrome DevTools プロトコル) と呼ばれるシリアライズされたメッセージング プロトコルを使用して、実行中のアプリを含むページと通信します。このプロトコルは ページ上の特定の DOM Node を強調表示するために `DOM.highlightNode` のようなメッセージを定義したり、ソースファイルの特定の場所にデバッガーを設定したりするために `Debugger.setBreakpoint` のようなメッセージを定義します。

Blazor WebAssembly デバッガー は、このプロトコルを利用することによって、ブラウザーで実行されているBlazor wasm アプリケーションのデバッグを容易にします。

`remote-debugging` プロパティにより、DevTools サービスがブラウザの外部で実行するポートを構成できます。デバッガーを Node.js のプロセスにアタッチしたり、あるエディターから JavaScript アプリケーションをデバッグしたことがある場合は、この機能を利用したことがあるはずです。Blazor wasm のデバッグではこれと同様の機能を利用します。


## The Debugging Proxy
デバッグ方法として標準化されたデバッガー上でエディターがアプリケーションと通信するような方法があります。これは、ディスク上のバージョンからトランスパイルまたは他の方法で変更されていないファイルに breakpoints (ブレイクポイント) をセットしようとしているようなプレーンの JavaScript では正常に機能します。一方、wasm をターゲットとするランタイムを介してブラウザー上で実行されている C# コードで構成されるアプリをデバッグしようとすると、話は大きく異なります。

これを解決するため、Blazor WebAssembly のデバッグ エクスペリエンスには、ブラウザーとエディター間に配置されるプロキシ コンポーネントが含まれています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150728/d3d8b17d-b8ba-5ffc-bb16-a73362ed4ebd.png)

このデバッギング プロキシは、キーボードショートカットからブラウザー内でデバッグセッションをアクティベートするか VS からデバッガーを初期化するときに起動される分離されている別のサーバープロセスです。

もしあなたが Visual Studio または Visual Studio Code で Blazor wasm をデバッグしている場合、`launchSettings.json` ファイルに設定されている `inspectUri`  というパラメーターに親しみがあると思われます。

```
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
```

`inspectUri` パラメーターは、デバッガーとのインターフェースとして、IDE が通信すべきこのデバッギング プロキシの WebSocket の URL を提供します。 


## Inside the Debugging Proxy

デバッギング プロキシが初期化されると、特定の Blazor wasm アプリに結び付いている全ての PDB (シンボルファイル) が、その DevTools インスタンスによって認識されるソースファイルとして読み込まれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150728/fcceec00-fa70-6034-ced3-4f2454bae559.png)

デバッギング セッションの残りの部分ではデバッギング プロキシによってデバッグを容易にします。具体的にはエディタが次のような `setBreakpointByUrl` リクエストを送信します。

```
{
    id: 0,
    method: "Debugger.setBreakpointByUrl",
    params: {
        lineNumber: 10,
        url: "file://Users/captainsafia/verifications/DebuggingTest/Pages/Counter.razor",
        columnNumber: 8
    }
}
```

デバッギング プロキシはこのメッセージをインターセプトし breakpoint をセットし、breakpoint が正常にセットされたことを通知するために Debugger.breakpointResolved メッセージを DevTools クライアントに送り返します。

デバッギング プロキシはこのメッセージ `Debugger.breakpointResolved` をインターセプトし、ブレークポイントをセットし、ブレークポイントが設定されたことを通知するメッセージを DevTools クライアントに送り返します。上記の順で "breakpoint をセットする" とはどういう意味でしょうか。

この "実際のデバッガー" とは、ランタイムの一部として実装されている Mono debugger です。ブレイクポイントがヒットした時に実行を一時停止されるように breakpoint をセットするにはデバッガーとのインターフェースが必要です。

## Conclusion

これで以上です。この実装について、私の気に入っているものの 1 つは、様々な異なるメッセージング プロトコルから様々な異なる通信プロトコルなど、たくさんの異なるコンセプトを互いにブリッジすることです。以下、全体の総括です。

- Blazor wasm のデバッグ エクスペリエンスは、Chrome DevTools Protocol 上に構築されています。
- Chrome DevTools Protocol は、エディターなどのクライアントが Chromium ベースのブラウザ (Google Chrome や New Microsoft Edge 等) で実行される Webアプリとの通信を可能にします。
- デバッギングプロキシは、IDE から送信されたメッセージをインターセプトし、Mono debugger 内で発生するアクションにそれらをマッピングします。


# おわりに
以上で [Under the hood with debugging in Blazor WebAssembly](https://safia.rocks/blog/blazor-wasm-debugging/) の Blog 記事のご紹介は終わりです。今回の訳による投稿の快諾をいただいた元記事の Safia Abdalla さんには大変感謝しております。Many thanks, Safia!!

本記事が Chromium ベースのブラウザを利用した Blazor wasm のデバッグに関する大枠の仕組みを知る入口になっていれば幸いです。また、ぜひもっと深堀りしてみたいといったきっかけにもなっていれば嬉しいです。

それでは本記事を閲覧いただき、ありがとうございました！！

#### 補足事項
- なお、本記事は 2020-11-12 時点の当該英語ブログ記事の翻訳となります。
- 訳が妥当なものが思いつかない部分は一部カタカナや英語表記で対応しました。また一部補足を付け足している部分もあります。
- もしかしたら翻訳の誤りや若干意訳で齟齬が出ている可能性もありますので、より正確な情報で見たい方は [原文](https://safia.rocks/blog/blazor-wasm-debugging/) の記事を見て頂くことをお勧めします。また、修正依頼など適宜何かあればぜひお知らせ下さい！