先ほど、自作の Service はすべて Program.cs に登録しなければならないと言いましたが、基本的な Service の中には自分で作らなくてもよいものもあります。
現在 Blazor が提供している組み込み Service は3つあります:
HttpClient:HTTP リクエストを処理します。ライフサイクルは Scoped です(注意:Blazor WebAssembly のみ提供されており、Blazor Server では自分で登録する必要があります)。IJSRuntime:JavaScript の機能を処理するための JavaScript runtime コンポーネントを提供します。Blazor WebAssembly のライフサイクルはSingleton、Blazor Server のライフサイクルはScopedです。NavigationManager:ルーティングと状態を処理します。Blazor WebAssembly のライフサイクルはSingleton、Blazor Server のライフサイクルはScopedです。
ライフサイクルとは Component が生存する時間を指し、Singleton と Scoped の他に Transient もあります。
Singleton:プログラムの起動から終了までインスタンスが1つだけ存在し、すべての Component がその1つのインスタンスを共有します。Transient:その Component を使用するたびに新しいインスタンスが生成されます。Scopedは少し特殊で、Blazor Server と Blazor WebAssembly で動作が異なります。Blazor Server のScopedは、HTTP リクエストのたびに新しいインスタンスが生成されることを意味しますが、Component 間で SingalR を介して受け渡しされる場合には新たなインスタンスは生成されません。Microsoft のドキュメントには「Blazor WebAssembly には現在 DI の概念はなく、ScopedはSingletonと同等である」と説明されています。
しかし筆者も当初は上記の説明を読んでもよくわからず、ある動画で GUID を使ったデモを見てようやく理解できました。試してみましょう。
まずインターフェース IGuidService を作成します。中には型が string のプロパティ UId だけがあります。次にクラス GuidService を作成し、コンストラクターの中でプロパティ UId を GUID 文字列で初期化します。そして Program.cs で AddTransient を使って登録します。

次に Guid.razor Component を作成します。中には3行だけで、ルートの定義、サービスの注入、GUID 文字列の表示が含まれます。このサンプルは非常に簡単なので ComponentBase は使用していません。そのため _Import.razor に @using BlazorServer.Services を追加する必要があります。最後に切り替えを容易にするため、NavMenu.razor に先ほど作成した Guid.razor を指す NavLink を定義します。

起動後、Post ページと Guid ページの間を切り替えても、ページを再読み込みしても、毎回新しい GUID が生成されているのがわかります。これが Transient の特性です。切り替えるたびに新しいインスタンスが生成されます。

次に登録方法を Singleton に変更します。すると、ページを再読み込みしても同じ GUID のままであることがわかります。これが Singleton の特性です。プログラムの起動から終了までインスタンスは1つだけです。

最後に登録方法を Scoped に変更します。Post ページに切り替えてから戻ってきても同じ GUID ですが、ページを再読み込みすると新しい GUID が生成されます。これが Scoped の特性です。HTTP リクエストが発生するたびに新しいインスタンスが生成され、Component 間では新しいインスタンスは生成されません。

上記の例は Blazor Server で行ったものです。Blazor WebAssembly で行うと、Singleton は Blazor Server とは異なる動作になります。その理由は、Blazor WebAssembly にはサーバー側がなく、ページを再読み込みするたびにアプリケーションがブラウザにダウンロードされるため、まったく新しい HTTP リクエストとなるからです。そのため、Singleton と Scoped はどちらも、ページを再読み込みするたびに新しいインスタンスが生成されます。


注:筆者は説明を簡潔にするために動画の一部を省略しています。詳しく知りたい方は各自ご研究ください。
引用:
- Blazor Course-Use ASP.NET Core to Build Full-Stack C# Web Apps
- ASP.NET Core Blazor dependency injection
注:本記事のコードは .NET 6 + Visual Studio 2022 でリファクタリングされています。原文リンクからリファクタリング後のコードと比較しながら学習していただければ幸いです。お読みいただきありがとうございます。原作者を応援してください。