Blazor WebAssembly を触る

先月 Blazor WebAssembly 3.2.0 がリリースされ、.NET Core 3.1.300 以降にアップデートすることで使用できるようになりました。

devblogs.microsoft.com

すでに Infragistics など著名な UI コンポーネントベンダーが対応しておりプロダクションレディな感じが漂っています。

WebAssembly 上に .NET CLR が実装され、Client と Server で共通の C# コードが動き、ASP.NET Core の要領でモダンな Web UI が作れるという、なんだかすごいフレームワークに興味津々で .NET Core を更新。

dotnet.microsoft.com

前回インストールして試してから1年近く経ってました。

blog.kondoumh.com

ブログにあるようにコマンドを実行。

f:id:kondoumh:20200618103342p:plain

localhost:5001 にアクセスすると、素敵な Webアプリが表示されます。

f:id:kondoumh:20200618104023p:plain

f:id:kondoumh:20200618104307p:plain

f:id:kondoumh:20200618104331p:plain

プロジェクトのファイルを覗くと ASP.NET MVC の Razor 構文に似たテンプレートと C# コードでできてます。

開発の雰囲気を掴むために、このアプリに何かページを追加してみます。

GitHub に ASP.NET Core Blazer の Extension が公開されてます。

github.com

Canvas では 2D グラフィックスや WebGL のレンダリングがサポートされてます。

github.com

これを使って Canvas に描画する Page を追加しようってことで dotnet add package を実行し Canvas 拡張を追加。

f:id:kondoumh:20200618123947p:plain

index.html に必要な JS ライブラリを追加。

<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>
    <script src="_content/Blazor.Extensions.Canvas/blazor.extensions.canvas.js"></script>
</body>

README に従って page (Canvas2D.razor) を追加

@page "/canvas2d"

<h1>Canvas 2D</h1>

<BECanvas Width="300" Height="400" @ref="_canvasReference" ></BECanvas>

@code {
    @using Blazor.Extensions
    @using Blazor.Extensions.Canvas
    @using Blazor.Extensions.Canvas.Canvas2D

    private Canvas2DContext _context;

    protected BECanvasComponent _canvasReference;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        this._context = await this._canvasReference.CreateCanvas2DAsync();
        await this._context.SetFillStyleAsync("green");

        await this._context.FillRectAsync(10, 100, 100, 100);

        await this._context.SetFontAsync("48px serif");
        await this._context.StrokeTextAsync("Hello Blazor!!!", 10, 100);
    }
}

Navigation に page を追加。iconify のアイコンを指定できるようです。

https://iconify.design/icon-sets/oi/

<div class="top-row pl-4 navbar navbar-dark">
    <a class="navbar-brand" href="">BlazorApp1</a>
    <button class="navbar-toggler" @onclick="ToggleNavMenu">
        <span class="navbar-toggler-icon"></span>
    </button>
</div>

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
             :
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="canvas2d">
                <span class="oi oi-map" aria-hidden="true"></span> Canvas 2D
            </NavLink>
        </li>
    </ul>
</div>

@code {
    private bool collapseNavMenu = true;

    private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;

    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
}

そして、dotnet run するとなんか出ました。

f:id:kondoumh:20200618125927p:plain

次に、WebGL グラフィックスを描画するサンプルです。こちらのテストプロジェクトからコードを持ってきました。

Canvas/test/Blazor.Extensions.Canvas.Test.ClientSide/Pages at master · BlazorExtensions/Canvas · GitHub

テストプロジェクト通りに razor ファイルと cs ファイルを分離して @inherits を使って書いてみたのですが、cs 側で持ってる BECanvasComponent 型のフィールドを暗黙型変換できないというエラーが解消できませんでした。仕方なく Canvas 2D 同様 razor の @code ブロックに直書きしました。

なんか出ました。

f:id:kondoumh:20200618214213p:plain

C# と Razor のコードしか書いてないので、昔ながらの ASP.NET MVC 開発の感覚になります。React や Vue でおなじみの Live Reloading 機能はまだないらしく、ファイルを編集したら Ctrl-C で中断し再び dotnet run してブラウザ側を更新・・というちょっとめんどくさいワークフローになってます*1

VS Code を当然使ってるわけですが、C# 拡張の他にデバッグのため JavaScript Debugger (Nightly) を導入することが推奨されています。

marketplace.visualstudio.com

launch.json の設定をして、デバッグ用の Chrome が起動したのですが、僕の環境ではブレークポイントで実行が止まってくれませんでした。

今回のお試しコード

dotnetcore-study/BlazorApp1 at master · kondoumh/dotnetcore-study · GitHub

Blazor アプリのホスティングモデルの説明を読むとブラウザで完結する Blazor WebAssembly モデルとBlazor サーバーモデルがあり、今回見たのは Blazor WebAssembly の方です。Blazor サーバーは、ASP.NET Core アプリで WASM が実行され、ブラウザと SignalR で通信します。Blazor サーバーモデルではブラウザが WASM 対応している必要はないようです。Blazor WASM モデルだと規模が大きくなってくると、ダウンロードやローディングの時間が気になるレベルになりそうです。

docs.microsoft.com

今回初めて触りましたが完成度高い感じしました。WASM を基盤としているため Silverlight のようなプラグインが不要なのと、まんま ASP.NET のプログラミングモデルということで C#er には受け入れられやすい気がします。

*1:やり方を知らないだけという可能性はあります。