LoginSignup
14
20

More than 3 years have passed since last update.

ASP.NET Core Blazor WebAssembly のハローワールド

Posted at

Blazor WebAssembly を試してみようかなと思い立ったので以下のドキュメントを写経してみました。

ASP.NET Core Blazor の概要

プロジェクトテンプレートのインストール

今のところプレビューなので自前で入れます。.NET Core SDk 自体も 3.1.102 以降である必要があります。私は、現時点での最新版の 3.1.201 が入っていました。以下のコマンドでプロジェクトテンプレートをいれます。

dotnet new -i Microsoft.AspNetCore.Components.WebAssembly.Templates::3.2.0-preview2.20160.5

入れると、Visual Studio のプロジェクトテンプレートの Blazor アプリの中に Blazor WebAssembly App が生えます。

image.png

右下の ASP.NET Core hosted にチェックを入れると、ASP.NET Core のプロジェクトも作れて、そこに WebAssembly も入れてデプロイ出来るので Azure WebApps とかにデプロイするのが楽そうなので、それのチェックを入れて作ります。

image.png

新規作成すると、以下のようなテンプレートが生成されます。
この段階で ASP.NET Core 側の API を叩いて画面に表示する例のコードまで入ってい
るのはありがたいですね。Server 側プロジェクトにある WetherForecastController が WebAPI です。

image.png

Client 側プロジェクトの Pages/FetchData.razor を見ると以下のように WetherForecast の URL 叩いています。いいね。

image.png

ローカル実行

何も考えずにローカル実行をするとブラウザーが立ち上がって WebAssembly の Blazor が動きますね。完璧。

image.png

Azure にデプロイ

Azure WebApps にデプロイしてみましょう。デプロイするのは Server 側のプロジェクトです。右クリックから発行を選びます。

image.png

適当に発行先を選んで(もしくは新規作成)デプロイをすると、本当にすんなりと動きます。

image.png

WebApp とかだと https://サイト名.azurewebistes.net/ 直下に作られるので気にしなくていいのですが、そうではなくて https://example.com/YourAppName/ のようなパスの下に展開されるときはアプリのベースパスの設定が必要なので、デプロイするときは、そこに気を付けましょう。

アプリのベース パス

起動シーケンスを少し見てみる

プレビューなのでデプロイまで、もう少しハマると思ったら、何もハマらなかったのでちょっと拍子抜けしました。少し WebAssembly 上での起動時のシーケンスでも追ってみようと思います。

Client 側プロジェクトには Program.cs があります。ここにある Main メソッドがクライアントサイドの C# としてのエントリーポイントになるでしょう。

見てみると以下のような感じで WebAssmeblyHostBuilder を作ってルートのコンポーネントの登録をしたり、Http 呼び出しに使う HttpClient クラスの登録をしてから実行してるように見えます。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Text;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace HelloBlazor.Client
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");

            builder.Services.AddBaseAddressHttpClient();

            await builder.Build().RunAsync();
        }
    }
}

App クラスはどうなっているかというと、ただの 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>

<Found Context="routeData"> の部分と <RouteView RouteData="@routeData" の routeData は、名前が一致していないといけないようですね。DefaultLayout は typeof(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>

@Body でレイアウトファイルを適用したファイルの中身が展開される場所なんでしょうね。

App.razor の Router タグは自動的に RouteAttribute が適用されているもの(.razor ファイル内で @page が指定されているもの)を探してくれます。

例えば Pages/Index.razor を見ると @page "/" と書かれています。

@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

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

これで、デフォルトの https://example.com/ などのような URL にアクセスされたときに自動的に Index.razor に行きつくようになっています。

Program.cs の builder の Services に自前クラスを追加することで DI も動きますね。

例えばこんな感じ MyClass を追加して…

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Text;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace HelloBlazor.Client
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");

            builder.Services.AddBaseAddressHttpClient();
            builder.Services.AddSingleton<MyClass>();

            await builder.Build().RunAsync();
        }
    }

    public class MyClass
    {
        public string Message => "Hello world";
    }
}

Index.razor などで使うには @inject クラス名 変数名 のような行を追加したらインジェクション出来ます。

@page "/"
@inject MyClass myClass

<h1>Hello, world!</h1>

<p>@myClass.Message</p>

Welcome to your new app.

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

FetchData.razor のように C# のコードを .razor の中に直接うめることは出来ますが、partial class を使って .cs ファイルに分離を出来ます。

部分クラスのサポート

まとめ

結構いい感じに出来そうですね。HTML/CSS は好きだけど JavaScript が苦手な人にはいいかもしれない。WebAssembly 系の弱点の起動処理が重い点を除けば…。

14
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
20