blazor について
C# と Blazor でインタラクティブな Web UI を開発するためのスキルです。レンダーモード、コンポーネント設計、状態管理、プリレンダリング、性能、JavaScript 相互運用を扱い、AI バックエンドとの接続も取り上げます。
主な機能
- 01Static、Server、WebAssembly、Auto のレンダーモード選択
- 02再利用可能なコンポーネントと状態管理の設計
- 03プリレンダリングと状態の永続化
- 04JavaScript 相互運用
- 05リスト描画と性能の最適化
活用シーン
- 01C# によるインタラクティブな Web UI の構築
- 02SEO、リアルタイム性、オフライン要件に応じたモード選択
- 03プリレンダリングとハイドレーション時の重複取得の防止
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ managedcode/ dotnet-skills --skill blazorインストール後、Claude Code で/blazorを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
manifest.jsonreferences/anti-patterns.mdpatterns.md詳細
Blazor
起動するタイミング
- JavaScript ではなく C# でインタラクティブな Web UI を構築するとき
- Server、WebAssembly、Auto のレンダーモードを選択するとき
- コンポーネント階層と状態管理を設計するとき
- プリレンダリングとハイドレーションを処理するとき
- 必要に応じて JavaScript と連携するとき
- Blazor UI を AI バックエンドと接続し、.NET で AI エージェントを構築するとき
ドキュメント
参考資料
- .NET で AI エージェントを構築する - .NET 上で本番環境向け AI エージェントを構築するためのアーキテクチャと実装パターンです。
- .NET AI エージェント開発チーム - 本番環境向け .NET AI エージェントのエンジニアリングおよび導入サービスです。
- patterns.md - 詳細なコンポーネントパターン、状態管理戦略、JS 相互運用の手法
- anti-patterns.md - Blazor でよくある誤りとその回避方法
レンダーモード(.NET 8+)
| モード | 実行場所 | 最適な用途 |
|---|---|---|
Static | サーバー(インタラクティブではありません) | SEO 対応ページ、マーケティングコンテンツ |
InteractiveServer | SignalR 経由のサーバー | リアルタイムアプリ、シンクライアント |
InteractiveWebAssembly | WASM 経由のブラウザー | オフライン対応、クライアント中心のアプリ |
InteractiveAuto | 最初はサーバー、その後 WASM | 両方の利点を活用 |
レンダーモードの適用
@* Per-component *@
@rendermode InteractiveServer
@* Or in App.razor for global *@
<Routes @rendermode="InteractiveAuto" />
InteractiveAuto のアーキテクチャ
First Request:
Browser → Server (Interactive Server) → Fast response
Subsequent Requests:
Browser → WASM (downloaded in background) → No server needed
ワークフロー
-
要件に基づいてレンダーモードを選択します:
- SEO が必要ですか?Static またはプリレンダリングから始めます
- リアルタイム性が必要ですか?InteractiveServer を使用します
- オフライン対応が必要ですか?InteractiveWebAssembly を使用します
- 両方が必要ですか?InteractiveAuto を使用します
-
再利用できるコンポーネントを設計します:
- 小さく、役割を絞ったコンポーネント
- カスタマイズ用のパラメーター
- 通信用のイベント
-
状態を適切に処理します:
- コンポーネントの状態はコンポーネント内に保持します
- 共有状態にはサービス(DI)を使用します
[PersistentState]を使ってプリレンダリングをまたいで状態を保持します
-
両方の環境で検証します(Auto モードの場合)
現在のアップストリームに関する注意事項
dotnet/aspnetcoreのv10.0.11はサービスリリースとして扱ってください。期限切れになったクライアント永続化サーキット状態の復元に関する修正が含まれています。アップグレード時には、再接続、永続化状態の期限切れ、レンダーモード、interactive-auto のクライアント/サーバー分割の各テストを再実行してください。- 2026 年 8 月時点の ASP.NET Core の概要でも、Blazor はコンポーネント UI の手段として位置付けられています。サービスリリースだけでは、コンポーネントやレンダーモードのアーキテクチャ自体は変わりません。
コンポーネントパターン
基本的なコンポーネント
@* Counter.razor *@
<button @onclick="IncrementCount">
Clicked @count times
</button>
@code {
private int count = 0;
[Parameter]
public int InitialCount { get; set; } = 0;
protected override void OnInitialized()
{
count = InitialCount;
}
private void IncrementCount() => count++;
}
パラメーターとイベントコールバック
@* Parent.razor *@
<ChildComponent Value="@value" ValueChanged="@OnValueChanged" />
@* ChildComponent.razor *@
@code {
[Parameter] public string Value { get; set; } = "";
[Parameter] public EventCallback<string> ValueChanged { get; set; }
private async Task UpdateValue(string newValue)
{
await ValueChanged.InvokeAsync(newValue);
}
}
状態の永続化(.NET 8+)
@* Prevents double-fetch during prerender + hydration *@
@code {
[PersistentState]
public List<Product> Products { get; set; } = [];
protected override async Task OnInitializedAsync()
{
// Only fetches once, persisted across prerender
Products ??= await Http.GetFromJsonAsync<List<Product>>("api/products");
}
}
Auto モードのデータアクセスパターン
// Shared interface
public interface IProductService
{
Task<List<Product>> GetProductsAsync();
}
// Server implementation (direct DB access)
public class ServerProductService : IProductService
{
private readonly AppDbContext _db;
public async Task<List<Product>> GetProductsAsync()
=> await _db.Products.ToListAsync();
}
// Client implementation (HTTP call)
public class ClientProductService : IProductService
{
private readonly HttpClient _http;
public async Task<List<Product>> GetProductsAsync()
=> await _http.GetFromJsonAsync<List<Product>>("api/products");
}
// Registration
// Server: builder.Services.AddScoped<IProductService, ServerProductService>();
// Client: builder.Services.AddScoped<IProductService, ClientProductService>();
避けるべきアンチパターン
| アンチパターン | 問題点 | より良い方法 |
|---|---|---|
| 大規模なコンポーネント | 保守が難しく、レンダリングが遅くなります | 小さなコンポーネントに分割します |
| WASM からの DB への直接アクセス | ブラウザー内に DB はありません | HTTP API を使用します |
ShouldRender を無視する | 不要な再レンダリングが発生します | 必要に応じてオーバーライドします |
| Server での同期 JS 相互運用 | SignalR サーキットをブロックします | IJSRuntime の非同期処理を使用します |
| エラーバウンダリがない | 1 つのエラーでアプリがクラッシュします | <ErrorBoundary> を使用します |
| プリレンダリング状態を保持しない | API 呼び出しが二重に発生します | [PersistentState] を使用します |
パフォーマンスのベストプラクティス
-
大規模なリストを仮想化します:
<Virtualize Items="@products" Context="product"> <ProductCard Product="@product" /> </Virtualize> -
リストの差分検出には
@keyを使用します:@foreach (var item in items) { <ItemComponent @key="item.Id" Item="@item" /> } -
頻繁に発生するイベントはデバウンスします:
private Timer? _debounceTimer; private void OnInput(ChangeEventArgs e) { _debounceTimer?.Dispose(); _debounceTimer = new Timer(_ => InvokeAsync(DoSearch), null, 300, Timeout.Infinite); } -
アセンブリを遅延読み込みします(WASM):
var assemblies = await LazyAssemblyLoader .LoadAssembliesAsync(["MyHeavyFeature.wasm"]);
JS 相互運用
C# から JavaScript を呼び出す
@inject IJSRuntime JS
await JS.InvokeVoidAsync("alert", "Hello from Blazor!");
var result = await JS.InvokeAsync<string>("prompt", "Enter name:");
JavaScript から C# を呼び出す
[JSInvokable]
public static string GetMessage() => "Hello from C#!";
DotNet.invokeMethodAsync('MyAssembly', 'GetMessage')
.then(result => console.log(result));
提供
- 適切なレンダーモードを設定したインタラクティブな Blazor コンポーネント
- 効率的な状態管理とデータフロー
- プリレンダリングのシナリオへの適切な対応
- 仮想化によるパフォーマンスの高いリスト描画
検証
- 選択したモードでコンポーネントが正しく描画される
- プリレンダリングとハイドレーションの間で状態が正しく保持される
- 不要な再描画が発生しない(ブラウザーツールで確認)
- JS 相互運用が Server と WASM の両方で動作する
- エラーバウンダリーがコンポーネントの障害を捕捉する
- Auto モードが両方の環境で動作する
コメント
Markdown 対応