mcpField
C
convert-blazor-server-to-webapp

convert-blazor-server-to-webapp

github.com/dotnet開発5.8k3.1k 回インストール1 日前に更新
リポジトリ

convert-blazor-server-to-webapp について

.NET 6/7 の Blazor Server アプリを、InteractiveServer の動作を保ちながら .NET 8 以降の Blazor Web App に移行する手順をエージェントに示すスキルです。コンポーネント構成、サービスやエンドポイントの変更、移行後の確認を扱います。

主な機能

  1. 01ターゲットフレームワークと関連パッケージの更新
  2. 02ルーティング内容を Routes.razor に移動
  3. 03_Host.cshtml を App.razor に変換
  4. 04Blazor サービスとエンドポイントの置き換え
  5. 05認証状態の移行とアプリの検証

活用シーン

  1. 01旧 Blazor Server アプリの .NET 8 以降への更新
  2. 02インタラクティブなサーバー描画を保った新モデルへの移行
  3. 03移行後のアンチフォージェリやプリレンダリング問題の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dotnet/skills --skill convert-blazor-server-to-webapp

インストール後、Claude Code で/convert-blazor-server-to-webappを入力して読み込まれたか確認します。

詳細

Blazor Server アプリを Blazor Web App に変換する

このスキルは、.NET 8 より前の Blazor Server アプリを .NET 8 以降の Blazor Web App に変換する際に、エージェントを支援します。従来のホスティングモデルでは、_Host.cshtml Razor Page をエントリーポイントとして、AddServerSideBlazor/MapBlazorHub を使用します。新しい Blazor Web App モデルでは、App.razor ルートコンポーネントとともに AddRazorComponents/MapRazorComponents を使用し、コンポーネント単位のレンダーモード、強化されたナビゲーション、ストリーミングレンダリングなど、.NET 8 以降の機能を利用できます。変換後のアプリでは、既存のインタラクティブな動作を維持するために InteractiveServer レンダーモードを使用します。

使用するタイミング

  • Blazor Server アプリを .NET 6 または .NET 7 から .NET 8 以降に移行する場合
  • アプリの Program.cs(または Startup.cs)で現在 AddServerSideBlazor() と MapBlazorHub() を使用している場合
  • アプリが Component Tag Helpers を使うホストページとして Pages/_Host.cshtml(または _Host.razor)を使用している場合
  • インタラクティブなサーバー側レンダリングを維持しつつ、新しい Blazor Web App の機能を採用したい場合

使用しないタイミング

  • アプリがすでに AddRazorComponents と MapRazorComponents を使用している場合。 すでに Blazor Web App であり、変換は必要ありません。ここで終了し、アプリがすでに Blazor Web App モデルを使用していることをユーザーに伝えてください。
  • Blazor WebAssembly アプリ、またはホスト型 Blazor WebAssembly アプリの場合 — これらには異なる移行手順があります
  • アプリを従来の Blazor Server ホスティングモデルのままにする場合(TFM とパッケージだけを更新します)
  • アプリのターゲットが .NET Framework の場合 — 先に .NET に移行する必要があります

入力

入力必須説明
Blazor Server プロジェクトはいBlazor Server アプリの .csproj とソースファイル
ターゲットフレームワークはい.NET 8 以降(例:net8.0、net9.0、net10.0)
Program.cs または Startup.csはいアプリのサービスとミドルウェアの構成
_Host.cshtml の場所推奨通常は Pages/_Host.cshtml。プロジェクトによっては _Host.razor の場合があります

ワークフロー

コミット戦略: 移行内容をレビューしやすくし、二分探索できるよう、論理的な各ステップの後にコミットします。

ステップ 1:プロジェクトファイルを更新する

.csproj ファイルを更新します。

  1. ターゲットフレームワークモニカー(TFM)をターゲットバージョンに変更します。
    <TargetFramework>net8.0</TargetFramework>
    
  2. すべての Microsoft.AspNetCore.*、Microsoft.EntityFrameworkCore.*、Microsoft.Extensions.*、および System.Net.Http.Json パッケージ参照を、対応するバージョンに更新します。

null 許容参照型、暗黙的な using、HTTP/3 サポートなど、Blazor 以外のプロジェクトファイルの変更については、ASP.NET Core の一般的な移行ガイドを参照してください。

ステップ 2:App.razor から Routes.razor を作成する

従来の App.razor には <Router> コンポーネントが含まれています。この内容を新しい Routes.razor ファイルに移動し、App.razor をルート HTML ドキュメントコンポーネントにできるようにします。

  1. プロジェクトのルートに新しいファイル Routes.razor を作成します。
  2. App.razor の内容全体を Routes.razor に移動します。
  3. 内容が <CascadingAuthenticationState> で囲まれている場合は、そのラッパーを削除します(ステップ 5 でサービスに置き換えます)。
  4. 次のステップで使うため、App.razor は空のままにします。

作成される Routes.razor は、次のようになります。

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(MainLayout)">
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

アプリが <RouteView> の代わりに <AuthorizeRouteView> を使用している場合は、そのまま残してください。Blazor Web App でも同じように機能します。

ステップ 3:_Host.cshtml を App.razor に変換する

Pages/_Host.cshtml の HTML シェルを、現在空の App.razor に移動し、Razor Page から Razor コンポーネントに変換します。

  1. Razor Page ディレクティブを削除する — @page "/"、@using Microsoft.AspNetCore.Components.Web、@namespace、@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers を削除します。

  2. コンポーネントのインジェクションを追加する — 環境に応じてエラー UI を表示する場合は、次を追加します。

    @inject IHostEnvironment Env
    
  3. ベースタグを修正する — <base href="~/" /> を <base href="/" /> に置き換えます。

  4. HeadOutlet コンポーネントタグヘルパーを置き換える — 次を置き換えます。

    <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
    

    次の内容に置き換えます。

    <HeadOutlet @rendermode="InteractiveServer" />
    
  5. App コンポーネントタグヘルパーを Routes に置き換える — 次を置き換えます。

    <component type="typeof(App)" render-mode="ServerPrerendered" />
    

    次の内容に置き換えます。

    <Routes @rendermode="InteractiveServer" />
    
  6. 環境タグヘルパーを置き換える — 次を置き換えます。

    <environment include="Staging,Production">
        An error has occurred. This application may no longer respond until reloaded.
    </environment>
    <environment include="Development">
        An unhandled exception has occurred. See browser dev tools for details.
    </environment>
    

    次の内容に置き換えます。

    @if (Env.IsDevelopment())
    {
        <text>
            An unhandled exception has occurred. See browser dev tools for details.
        </text>
    }
    else
    {
        <text>
            An error has occurred. This app may no longer respond until reloaded.
        </text>
    }
    
  7. Blazor スクリプトを更新する — 次を置き換えます。

    <script src="_framework/blazor.server.js"></script>
    

    次の内容に置き換えます。

    <script src="_framework/blazor.web.js"></script>
    
  8. レンダーモードのインポートを追加する — _Imports.razor に次を追加します。

    @using static Microsoft.AspNetCore.Components.Web.RenderMode
    
  9. Pages/_Host.cshtml を削除する(存在する場合は Pages/_Host.cshtml.cs も削除します)。

プリレンダリングに関する注意: 元のアプリで render-mode="Server"("ServerPrerendered" ではなく)が使われていた場合、プリレンダリングは無効でした。この状態を維持するには、HeadOutlet と Routes の両方で InteractiveServer の代わりに new InteractiveServerRenderMode(prerender: false) を使用します。

ステップ 4:Program.cs を更新する

Program.cs(古いホスティングパターンを使用しているアプリでは Startup.cs)に次の変更を加えます。

  1. Blazor Server サービスを置き換える — 次を置き換えます。

    builder.Services.AddServerSideBlazor();
    

    次の内容に置き換えます。

    builder.Services.AddRazorComponents()
        .AddInteractiveServerComponents();
    

    AddServerSideBlazor にオプション(回線オプション、ハブオプション、詳細なエラーなど)が設定されていた場合は、それらを AddInteractiveServerComponents に移行します。

    // Old:
    builder.Services.AddServerSideBlazor(options =>
    {
        options.DetailedErrors = true;
        options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(10);
    });
    
    // New:
    builder.Services.AddRazorComponents()
        .AddInteractiveServerComponents(options =>
        {
            options.DetailedErrors = true;
            options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(10);
        });
    
  2. Blazor エンドポイントのマッピングを置き換える — 次を置き換えます。

    app.MapBlazorHub();
    

    次の内容に置き換えます。

    app.MapRazorComponents<App>()
        .AddInteractiveServerRenderMode();
    

    App が App.razor コンポーネントとして解決されるよう、プロジェクトのルート名前空間を参照する using ステートメントがあることを確認します。

  3. フォールバックルートを削除する — 次を削除します。

    app.MapFallbackToPage("/_Host");
    
  4. 明示的なルーティングミドルウェアを削除する — 存在する場合は次を削除します。

    app.UseRouting();
    

    エンドポイントルーティングが既定で有効なため、明示的な UseRouting() は不要になりました。

  5. アンチフォージェリーミドルウェアを追加する — UseAuthentication/UseAuthorization がある場合は、その後に次を追加します。

    app.UseAntiforgery();
    

    AddRazorComponents はアンチフォージェリーサービスを自動的に登録しますが、ミドルウェアはパイプラインに明示的に追加する必要があります。追加しない場合、フォームの POST リクエストは 400 エラーで失敗します。

ステップ 5:CascadingAuthenticationState を移行する(使用している場合)

ルーターを <CascadingAuthenticationState> でラップしていた場合:

  1. <CascadingAuthenticationState> コンポーネントのラッパーを削除します(この手順に従っていれば、ステップ 2 ですでに削除されています)。
  2. Program.cs にカスケード認証状態サービスを追加します。
    builder.Services.AddCascadingAuthenticationState();
    

Blazor Web Apps では、コンポーネントラッパーを使う方法はレンダーモードの境界を越えて機能しません。サービスを使う方法では、レンダーモードにかかわらず、すべてのコンポーネントに Task<AuthenticationState> がカスケード値として提供されます。

ステップ 6:推奨される改善(任意)

これらは任意のモダナイゼーション改善であり、移行を機能させるために必須ではありません。これらを提案する場合は、任意であることを明記してください。

  • UseStaticFiles を MapStaticAssets に置き換える(.NET 9+):app.MapStaticAssets() は、フィンガープリント、事前圧縮、コンテンツベースの ETag による最適化された静的ファイル配信を提供します。MapStaticAssets のドキュメントを参照してください。
  • 非同期データ読み込み(OnInitializedAsync)を行うページに @attribute [StreamRendering] を追加する と、体感パフォーマンスが向上します。ページは最初の同期コンテンツをすぐにレンダリングし、非同期データが届くと再レンダリングします。
  • <link> タグが _Host アセンブリ名を参照していた場合は、CSS 分離バンドルの参照を更新し、プロジェクトの実際のアセンブリ名と一致していることを確認します:<link href="{AssemblyName}.styles.css" rel="stylesheet" />。
  • その他の Blazor 以外の改善(最小ホスティング、HTTP/3、出力キャッシュなど)については、ASP.NET Core の一般的な移行ガイドを参照してください。
ステップ 7:移行を検証する
  1. 新しいフレームワークを対象にプロジェクトをビルドします。コンパイルエラーがないことを確認してください。
  2. 削除された API の参照が残っていないか検索します:
    • AddServerSideBlazor
    • MapBlazorHub
    • MapFallbackToPage
    • blazor.server.js
    • _Host.cshtml
  3. アプリを実行して、次の点を確認します:
    • ページが正しく読み込まれ、レンダリングされる
    • インタラクティブ機能(フォーム、イベントハンドラー、SignalR 回線)が動作する
    • ページ間のナビゲーションが動作する
    • 認証および認可のフローがある場合、それらが動作する
  4. 既存のテストを実行します。

検証

  • AddServerSideBlazor への参照が残っていない
  • MapBlazorHub への参照が残っていない
  • MapFallbackToPage("/_Host") への参照が残っていない
  • blazor.server.js への参照が残っていない
  • Pages/_Host.cshtml が削除されている
  • App.razor が、完全な HTML ドキュメント構造を持つルートコンポーネントとして機能している
  • Routes.razor に <Router> の設定が含まれている
  • Program.cs で AddRazorComponents().AddInteractiveServerComponents() が使用されている
  • Program.cs で MapRazorComponents<App>().AddInteractiveServerRenderMode() が使用されている
  • ミドルウェアパイプラインに app.UseAntiforgery() が含まれている
  • アプリで <CascadingAuthenticationState> を使用していた場合、AddCascadingAuthenticationState() サービス登録に置き換えられている
  • 対象のフレームワークでアプリが正常にビルドおよび実行される

よくある落とし穴

落とし穴解決策
UseAntiforgery() ミドルウェアがないAddRazorComponents は偽造防止サービスを登録しますが、ミドルウェアは明示的に追加する必要があります。app.UseAntiforgery() は UseAuthentication/UseAuthorization の後に配置してください。これがないと、フォームの POST リクエストが 400 エラーで失敗します。
blazor.server.js を blazor.web.js に置き換えていない古いスクリプトは Blazor Web App モデルでは動作しません。_framework/blazor.server.js への参照をすべて _framework/blazor.web.js に置き換えてください。
<CascadingAuthenticationState> ラッパーを削除していないBlazor Web Apps では、コンポーネントのラッパーはレンダーモードの境界を越えて機能しません。代わりに builder.Services.AddCascadingAuthenticationState() を使用してください。
パイプラインに app.UseRouting() を残している明示的な UseRouting() は不要になっており、エンドポイントルーティングに干渉する場合があります。他のミドルウェアで特に必要とされない限り、削除してください。
プリレンダリングが無効だったのに InteractiveServer を使用している元のアプリで render-mode="Server"("ServerPrerendered" ではない)を使用していた場合は、同じ動作を維持するために new InteractiveServerRenderMode(prerender: false) を使用してください。InteractiveServer を使用するとプリレンダリングが有効になり、初期化時に JS 相互運用に依存するコンポーネントで予期しない問題が発生することがあります。
AddServerSideBlazor のサーキットオプションを移行していないサーキットオプション、ハブオプション、または詳細なエラー設定を構成していた場合は、AddInteractiveServerComponents(options => { ... }) に移行してください。そうしないと、それらの設定は通知なく失われます。
UseAntiforgery() を認証ミドルウェアより前に配置している偽造防止ミドルウェアは UseAuthentication と UseAuthorization の後に配置する必要があります。これより前に配置すると、ユーザーの ID が確立される前に偽造防止の検証が実行されます。
CSS 分離バンドルのリンクでアセンブリ名が間違っている<link href="{Name}.styles.css"> タグが古いプロジェクト名を参照していた場合は、現在のアセンブリ名に合わせて更新してください。

詳細情報

コメント