🦁

.NET 8 で Blazor Server をする方法 (消えた Blazor Server テンプレート)

2023/08/08に公開

.NET 8 の開発も着々と進んで Preview 6 が現在リリースされている状態です。この後 Preview 7 -> RC1 -> RC2 といって 11 月に .NET 8 が正式リリースになる予定です。.NET Conf の日付も発表されているので、そこにあわせて行くのだと思います。

ここでは、.NET 8 Preview 6 で消えた Blazor Server のテンプレート相当のことを .NET 8 でやる方法について書いていきます。

消えた Blazor Server テンプレート

ということで本題ですが、.NET 8 Preview 6 で Blazor Server のプロジェクトテンプレートが消えました。新たに Blazor Web アプリというプロジェクトテンプレートが作られています。これは Blazor United という名前で呼ばれていた全てのタイプの Web アプリを Blazor で作れるようにするというコンセプトで追加された様々な機能強化を取り込んだ形の新しい Blazor のプロジェクトテンプレートになります。

このプロジェクトテンプレートを使うと今までの Blazor のように、変態的な動作モデル (WebSocket の接続が作られてサーバーサイドでボタンクリック処理などが動くモデルや、WebAssembly で動くようなモデル) ではなく、割と素直なタイプの Web アプリのように動くものが作られます。そこに対して部分的に Blazor Server や Blazor WebAssembly を仕込んだりすることが出来ます。

ただ、そうはいっても過去に Blazor Server で全体を作っていたというような形で作りたい人もいると思います。ここでは、現時点でそれを実現する方法を紹介します。

やってみよう

Blazor Web アプリの作成

普通に作ります。作成時に「対話型サーバーコンポーネントを使用する」というオプションがありますが、これをやるとカウンターコンポーネントが追加されて、それが Blazor Server のモデルで動くようになるコードが追加されます。これをしてもいいですが、ここではやらないでおきます。

Blazor Server の有効化

先ほどのプロジェクト作成時に「対話型サーバーコンポーネントを使用する」にチェックを入れている場合には自動的に追加されるコードを手動で追加していきます。
Program.cs に AddRazorComponents() を呼び出している箇所があるので、そこに対して AddServerComponents() を追加します。そして MapRazorComponents<App>() に対して AddServerRenderMode() を追加します。

Program.cs
using BlazorApp9;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorComponents()
    .AddServerComponents(); // これを追加

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.MapRazorComponents<App>()
    .AddServerRenderMode(); // これを追加

app.Run();

Razor の言語バージョンを 8 にする

これはプレビュー版でのみ必要な手順になります。今後の Preview 7 や RC の何処かのタイミングで不要になります。
プロジェクトファイルに <RazorLangVersion>8.0</RazorLangVersion> を追加します。

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <RazorLangVersion>8.0</RazorLangVersion>
  </PropertyGroup>

</Project>

アプリ全体を Blazor Server として動くようにする

先ほどの RazorLangVersion を指定することでコンポーネント単位で Blazor Server のモデルで動かすことが出来る属性が指定出来るようになっています。
それを適用するための下準備として AppRouter.razor という名前でコンポーネントを作成して App.razor から Router の定義をコピペして以下の様にします。

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

そして App.razor にある Router の定義を AppRouter で置き換えます。この時 @rendermode="@RenderMode.Server" を属性に指定して Blazor Server の形で動くように指定します。

App.razor
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>BlazorApp9</title>
    <base href="/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link rel="stylesheet" href="css/bootstrap-icons/bootstrap-icons.min.css" />
    <link rel="stylesheet" href="css/app.css" />
    <link rel="icon" type="image/png" href="favicon.png" />
    <link rel="stylesheet" href="BlazorApp9.styles.css" />
    <HeadOutlet />
</head>

<body>
    <AppRouter @rendermode="@RenderMode.Server" />

    <script src="_framework/blazor.web.js" suppress-error="BL9992"></script>
</body>
</html>

これで実行すると、以下のように Blazor Server でよく見る WebSocket の接続が張られていることが確認出来ます。

後は普通にページを追加して開発できます。

まとめ

部分的に Blazor Server に出来たりするので、ほぼ全体を Blazor Server で動くようにすれば実質 Blazor Server になるということになります。

Microsoft (有志)

Discussion