はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Blazor】BlazorでASP.NET Coreを使用した最初のWebアプリをビルドする公式ドキュメントを読んだメモ①

はじめに

ふと興味本位でBlazorを触ってみようと思い、以下の公式のラーニングパスをやってみてます。
learn.microsoft.com

そのときに学んだことをメモがてらに残しておきたいと思います。正直自分宛のメモなので、気になる方は公式のものをみてください。

ダウンロード&インストール

.NET 8 SDKがインストールされていることを確認してください。

$ dotnet --version
8.0.100

されていない場合はインストールします。
https://download.visualstudio.microsoft.com/download/pr/3b11b408-68e1-4a8f-a0ad-55b21456c4f6/03819d38c79a9aa4fd806f8c7b64130d/dotnet-sdk-8.0.101-osx-x64.pkg

アプリの作成

アプリの作成はdotnet new blazorコマンドを利用します。

$ dotnet new blazor -o MyFirstBlazorApp
テンプレート "Blazor Web アプリ" が正常に作成されました。
このテンプレートには、Microsoft 以外のパーティのテクノロジーが含まれています。詳しくは、https://aka.ms/aspnetcore/8.0-third-party-notices をご覧ください。

作成後の操作を処理しています...
/Users/user/Blazor/MyFirstBlazorApp/MyFirstBlazorApp.csproj を復元しています:
復元対象のプロジェクトを決定しています...
/Users/user/Blazor/MyFirstBlazorApp/MyFirstBlazorApp.csproj を復元しました (182 ms)。
正常に復元されました。
生成されたファイル
  • Program.cs は、サーバーを起動するアプリのエントリ ポイントであり、アプリ サービスとミドルウェアを構成する場所です。
  • App.razor は、アプリ向けルート コンポーネントです。
  • Routes.razor は、Blazor ルーターを構成します。
  • Components/Pages ディレクトリには、アプリ向けのサンプル Web ページが含まれています。
  • BlazorApp.csproj では、アプリ プロジェクトとその依存関係を定義しています。
  • Properties 内の launchSettings.json は、ローカル開発環境のさまざまなプロファイル設定を定義します。ポート番号は、プロジェクトの作成時に自動的に割り当てられ、このファイルに保存されます。

Blazor チュートリアル | 最初の Blazor アプリをビルドする

アプリを実行する

アプリを実行するにはdotnet watchを利用します。

$ dotnet watch
dotnet watch 🔥 Hot reload enabled. For a list of supported edits, see https://aka.ms/dotnet/hot-reload.
  💡 Press "Ctrl + R" to restart.
dotnet watch 🔧 Building...
  復元対象のプロジェクトを決定しています...
  復元対象のすべてのプロジェクトは最新です。
  MyFirstBlazorApp -> /Users/user/Blazor/MyFirstBlazorApp/bin/Debug/net8.0/MyFirstBlazorApp.dll
dotnet watch 🚀 Started
warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
      No XML encryptor configured. Key {----} may be persisted to storage in unencrypted form.
info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5226
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /Users/user/Blazor/MyFirstBlazorApp
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
      Failed to determine the https port for redirect.

http://localhost:<port number>を開くとBlazorアプリが実行されているはずです。


カウンターの実装について

サンプルコード上でのカウンター実装について見てみます。該当ファイルはComponents/Pages/Counter.razorです。

カウンター
@page "/counter"
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

@page "/counter"よりブラウザでhttp://localhost:5226/counterのように指定するとCounterコンポーネントの内容がレンダリングされ、@rendermode InteractiveServerを用いることでブラウザからユーザーインターフェイスイベントを処理できるようになります。

buttonがクリックされるとonclickイベントが発生し、IncrementCountメソッドが実行、currentCountが増分してコンポーネントがレンダリングされます。

@codepage, @rendermodeといったRazorディレクティブの詳細を知りたい方は公式ドキュメントをご覧ください。

コンポーネント

.razorファイルは再利用可能なUIコンポーネントが定義されています。

コンポーネントパラメーターを定義することで、属性または子コンテンツを使用して指定され、それは子コンポーネントのプロパティを設定できます。

@page "/counter"
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    // Parameter属性を渡すことでコンポーネントパラメーターとして扱えるようになる
    [Parameter] public int IncrementAmount { get; set; } = 1;

    private void IncrementCount()
    {
        currentCount += IncrementAmount;
    }
}
<!-- コンポーネントパラメーターを渡す -->
<Counter IncrementAmount="10" />

データバインディングとイベント

C#色の値をレンダリングする場合は先頭に@を使用します。

<p role="status">Current count: @currentCount</p>
<!-- @の開始と終了を明示的に指定した場合 -->
<p role="status">Current count: @(currentCount)</p>

制御フローを追加する

<!-- 条件付きでレンダリング -->
@if (currentCount > 3)
{
    <p>You win!</p>
}
<!-- コレクションの一覧をレンダリング -->
<ul>
    @foreach (var item in items)
    {
        <li>@item.Name</li>
    }
</ul>

@if@foreachといったRazorディレクティブの詳細を知りたい方は公式ドキュメントをご覧ください。

イベントを処理する

UI 要素からイベントのイベント コールバックを指定するには、@on で始まり、イベント名で終わる属性を使用します。

  • @onclick
  • @onchange
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount += 1;
    }
}
描画されている様子
<input @onchange="InputChanged" />
<p>@message</p>

@code {
    string message = "";

    void InputChanged(ChangeEventArgs e)
    {
        message = (string)e.Value;
    }
}
描画されている様子

データバインディング

UI要素の値が変更されたときにコードの値も変更され、コードの値が変更されたときにUI要素の表示も変わる、双方向データバインディングを設定するには@bind属性を利用します。

<input @bind="text" />
<button @onclick="() => text = string.Empty">Clear</button>
<p>@text</p>

@code {
    string text = "";
}
描画されている様子

TODOリスト作成

<!-- Todo.razor (Pages以下に配置) -->
@page "/todo"
@rendermode InteractiveServer

<h3>Todo (@todos.Count(todo => !todo.IsDone))</h3>

<ul>
    @foreach (var todo in todos)
    {
    <li>
        <input type="checkbox" @bind="todo.IsDone" />
        <input @bind="todo.Title" />
    </li>
    }
</ul>

<input @bind="newTodo" />
<button @onclick=AddTodo>Add todo</button>

@code {
    private List<TodoItem> todos = new();
    string newTodo = "";
    
    void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}
// TodoItem.cs (プロジェクトルートに配置)
public class TodoItem
{
    public string? Title { get; set; }
    public bool IsDone { get; set; } = false;
}
TODOリストの完成図

さいごに

ひとまずBlazorをしようしたWeb開発の概要 ~ Blazorを使用してTODOリストを作成するまでやりました。気が向いたらこの先も進みたいと思います。