Blazor WebAssembly に入門してみた

2021.07.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

いわさです。

WebアプリケーションのクライアントサイドをC#で実装出来る Blazor という技術があります。
弊社でも以前取り扱った記事があります。

実は、Blazorには Blazor Server と Blazor WebAssembly の2種類があります。
上記記事はBlazor Serverに関する記事となりまして、SPAなど検討される場合は Blazor WebAssembly が選択肢となってきます。

本日は Blazor WebAssembly に入門してみました。
ちょっと悩んだのですが WebAssemblyとはなんぞやという座学から入るのはやめて、一旦この記事では、Visual Studio for Mac での実行と、ソリューション構成の解析から入門するというアプローチを取ってみようかなと思います。

Visual Studio for Macでとりあえず実行してみる

Visual Studio 2019 でも Visual Studio 2019 for Mac でも動作するのですが、今回は macOSで実行します。
デフォルトでプロジェクトテンプレートが用意されています。

テンプレートからソリューションが作成されたら、すぐ実行してしまいましょう。
ビルドされ、その後 localhost でのブラウザが立ち上がります。

ローディングが表示されて...

コンテンツが表示されました。
ここまでブラウザ上でページ全体をレンダリングしているような挙動が無いのでSPA感ありますね。

サイドメニューを操作してみましょう。
こちらも同様にクライアントサイドで処理されている様子です。

ソリューション構成

初見は何がなんだかわかりませんでした。
具体的には、何がサーバーサイドで何がクライアントサイドなのかわからず混乱しました。

アプリケーションのエントリがどこなのかわからなかったのです。
Program.csを見て、「なんだろうこれは・・・」と思っていました。

一旦、Program.csは無視しましょう。
このソリューションではサーバーサイドロジックは実装されておらず、wwwrootディレクトリ以下の静的なサーバーサイドコンテンツが存在しているだけと解釈して良さそうです。

クライアントはリクエストに対するレスポンスとして、index.htmlを受けます。
ブラウザの"ページのソースを表示"する機能を使って見てみます。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>iwasa-blazor</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
</head>

<body>
    <app>Loading...</app>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">?</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

特にサーバーサイドでレンダリングしている様子もないですね。
Chromeのデベロッパツールでも確認してみます。

先程の「ページのソースを表示」で確認したHTMLと差分がありますね。
赤枠の部分がクライアントサイドで動的にレンダリング・追加された部分と解釈して良さそうです。 先程のHTMLから推察するにこの動作を担っていそうなのは_framework/blazor.webassembly.jsくらいですね。

このJSファイルの中身は膨大なので、入門段階では追う必要はないです。
以下に概要の記載がありますので抜粋します。

blazor.webassembly.js スクリプトは、フレームワークによって提供され、次の処理を行います。

  • .NET ランタイム、アプリ、およびアプリの依存関係のダウンロード。
  • アプリを実行するランタイムの初期化。

blazor.webassembly.jsによって、Blazor WebAssembly に必要な初期化処理が実行され、クライアントサイドでProgram.csが実行されていそうです。

どういうページがどのようにレンダリングされるかについては以下へ記載があります。

上述のとおり、Pagesディレクトリ配下のファイルには@pageディレクティブの記載がありました。

Pages/Index.razor

@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

App.razorがルートテンプレートで、以下のようになっています。

App.razor

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

@pageディレクティブに該当ページのURLルーティング情報を記述し、ルートテンプレートでレイアウト(上記だとDefaultLayout属性のMainLayout)を指定している感じですね。

そしてMainLayoutは以下のようになっています。

Shared/MainLayout.razor

@inherits LayoutComponentBase

<div class="sidebar">
    <NavMenu />
</div>

<div class="main">
    <div class="top-row px-4">
        <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
    </div>

    <div class="content px-4">
        @Body
    </div>
</div>

これが共通レイアウトで、左にサイドバー(NavMenu)で右側にメインコンテンツを@Bodyディレクティブでレンダリング位置を指定していますね。

まとめ

なんとなくBlazor WebAssemblyの入門段階の大枠はつかめた気がします。

  • Blazor Server と Blazor WebAssembly がある
  • クライアントサイドでJavaScriptを使って初期化処理を行い、その後.NETコードが実行されている
  • Razorテンプレートで各ディレクティブを使ってレイアウトやコンポーネントの部品化がされている

今回理解した内容で、どこを変更するとどう変わるかイメージがつきそうです。
次回以降は少しカスタマイズしてみます。

参考