Webアプリ

【C#、Blazor】Webアプリ開発入門編(4)「Todoアプリ」でデータベース作成&データ表示 ~データベース操作のフレームワークを学ぶ~

今回から具体的なTodoリストアプリ開発を題材として、Blazorの基本機能について紹介します。

初心者がBlazorでWebアプリ開発をする際にまず押さえるべき以下の要点に絞って解説したいと思います。

  • C#コードとHTMLを組み合わせて動的なページを作るRazorコンポーネント
  • データベース(DB)アクセスを行うためのEntity Framework Core
  • 認証基盤であるASP.NET Core Identity

「最終ゴール」は、認証機能付きでDBへの参照・更新操作を行う簡易なTodoリストアプリを作ることです。

今回の記事ではその「第一歩目」として、DBへ参照してTodoリストを表示する機能を作ります。

Todoリストアプリは簡単なものですが、BlazorによるWebアプリ開発におけるエッセンスが詰まっています。

これからのWebアプリ開発の土台になる部分なので、一緒にしっかり学んでいきましょう!

演習のコードはGitHubで公開していますので、そちらも参考にしてください。

YouTubeの動画も作っていますので、よかったら見てください。

講義:Blazor開発の基本と今回作るTodoリストアプリ

Blazorを用いたWebアプリ開発の基本

Blazorを用いたWebアプリの典型的な実装方法は、以下のようになります。

Webアプリはクライアントサイド(Webアプリの見た目)とサーバサイド(データの処理・保管)で構成されます。

また、サーバサイドはデータの処理を行うビジネスロジックと、データの保管を行うデータベース(DB)で構成されます。

(1)Razorコンポーネントで実装

RazorコンポーネントはRazor記法とC#コードを組み合わせて記述され、動的で対話的なWebアプリの画面UIとなります。

Raozrコンポーネントは部品化することで再利用も可能です。

(2)Serviceクラスとして実装

Blazorアプリのビジネスロジックは、Serviceクラスとして実装します。

Serviceクラスは、Entity Framework Core(EF Core)を使用してDBアクセスを行い、アプリに必要なデータの処理を担当します。

(3)EF Coreを用いコードファーストで構築

EF Coreのコードファーストアプローチを用い、C#クラスでDBスキーマを表現します。

開発者はC#コードでデータモデルを定義し、EF Coreがそのモデルに基づいて自動的にデータベーススキーマを生成および更新します。

これにより、データモデルに変更があった場合、C#コードを修正するだけで済み、データベーススキーマとの同期が保たれます。

(4)認証機構をASP.NET Core Identityで実装

ASP.NET Core Identityは、ユーザー認証に必要な機能を提供し、EF Coreと連携して動作します。

これにより、ユーザのログイン・ログアウトなどの機能を簡単に実装可能です。

Core Identityは、Razorコンポーネント・Serviceクラス・EF Coreと連携し、アプリケーション全体でシームレスに認証機能を提供します。

プロ美

いろいろあって難しいなぁ…。

プロ太

具体例を見るとわかりやすいかと思います。

演習では簡単なTodoリストアプリ開発を題材として、(1)~(4)の理解を深めていきましょう!

Webアプリの基本について以下の記事も参考にしてください。

Webアプリとは何か?~Webアプリ開発がプログラミング学習にもおすすめな理由~ プログラミングの基礎をいったん一通り学んだら、次のステップとして何かアプリケーションを作ってみるとよいでしょう。 Webアプリケ...

DBへのアクセス・管理方法や認証機構には上述したもの以外にも様々な選択肢があります。

例えば、既存のDBを流用したい場合はコードファーストではなくDBファーストのアプローチが良いかもしれません。

また、認証機構についても例えばクラウドベースの認証(例:Azure AD B2C)を選ぶことも可能です。

まずは典型的な実装方法をおさえ、そこから自分が作りたいアプリの要件にあわせて、他の選択肢について学ぶとよいです!

Todoリストアプリ

最終的にどのようなTodoリストアプリを作るか、また今回の演習でどの部分を作るかを説明します。

作る機能と学ぶこと

Todoリストアプリを以下のように段階的に作り上げていきます。

  • 【1】Todoリストを一覧で表示できる。(←今回の演習)
  • 【2】Todoを削除、編集、追加できる。
  • 【3】ユーザごとにTodoリストを管理できる。
  • 【4】画面入力に対してバリデーションを行える。
  • 【5】DB更新の結果(成功・失敗)を画面UI上に表示できる。

【1】、【2】でRazorコンポーネントの使い方とEF CoreによるDB管理やCRUD操作の方法を説明します。

CRUDは、DB操作の基本的な4つの機能を表す頭字語です。

  1. Create(作成)
  2. Read(読み取り)
  3. Update(更新)
  4. Delete(削除)

今回が参照系(Read)、次回は更新系(Create、Update、Delete)となります。

【3】でCore Identityによるユーザ認証機構を説明します。

【4】、【5】では入力バリデーションやDB更新結果をユーザへフィードバックする仕組みについて説明します。

使用する「Blazorのモード」と「DB」

BlazorアプリのモードとしてはServerモード、DBはSQLiteを使います。

Blazor Serverモードはアプリ開発が容易です。サーバ側でアプリが実行されるため、クライアントとサーバ間のデータのやり取りが簡易です。

SQLiteは軽量でシンプルなDBであり導入が容易です。単一のファイルにデータを保存するため管理が簡単です。

WASMモードを使う場合でも、Razorコンポーネントの使い方などはServerモードと変わらないため、そのまま利用できます。

また、EF Coreを使っていれば別のDB(例:SQLServer、PostgreSQL)へ入れ替えるのも容易です。

Blazorの実行モード(Serverモード、WASMモードなど)について復習したい方は以下の記事も参考にしてください。

【C#、Blazor】Webアプリ開発入門編(1)Blazorとは? ~Webアプリ開発フレームワークでBlazorを選ぶ理由~ 今回はWebアプリ開発フレームワーク「Blazor」について解説します。 フレームワークとは、ソフトウェア開発で使える既製の枠組...

演習:Todoリストを一覧で表示 ~EF Coreとコードファースト~

Todoリストを一覧表示する機能を次の手順で作ります。

  • 手順1:プロジェクトひな型作成
  • 手順2:Gitリポジトリを作成
  • 手順3:データモデル定義とDBへのマイグレーション
  • 手順4:ServiceクラスでDB参照を実装
  • 手順5:Todoリスト表示用のRazorコンポーネントを実装

手順1:プロジェクトひな型作成

プロジェクトを配置するフォルダを作成し、シェル(PowerShell等)でそのフォルダへ移動します。

以下のコマンドでBlazorアプリのひな型プロジェクトを作成します。

dotnet new blazor -n TodoListApp -o TodoListApp -f net8.0 --interactivity Server -au Individual --use-local-db false

Serverモードのプロジェクトを作成するので「–interactivity Server」、SQLiteを使うので「–use-local-db false」のオプションをそれぞれ指定します。

Visual Studioでプロジェクトファイル「TodoListApp.csproj」を開きます。
(この時点では、ソリューションファイルはまだ作られていません)

「ファイル>全て保存」で、「TodoListApp.csproj」と同じフォルダへソリューションファイル「TodoListApp.sln」を保存しておきましょう。

以降はこのプロジェクトのVisual Studioで開くときには「TodoListApp.sln」を開きます。

手順2:Gitリポジトリを作成

Gitリポジトリも作成しておきましょう。

今回のTodoリストアプリを作成する上で、Gitリポジトリ作成は必須ではありません

ですが、本格的にWebアプリ開発を行う上でバージョン管理は必要不可欠なため、練習として作ります!

TodoListApp.slnが存在するフォルダで以下のコマンドを実行し、Git管理対象外のファイルを指定するための.gitignoreファイルを作ります。

dotnet new gitignore

.gitignoreファイルができたら、ファイルを開き末尾に以下を追記しましょう。

# SQLite
Data/*.db
Data/*.db-shm
Data/*.db-wal

これで、Dataフォルダ配下にあるSQLite関連ファイルはGitによる管理の対象外となります。

ユーザ情報の設定がまだ設定されていない場合は、例えば以下のように設定します。

git config user.name "プロ太"
git config user.email "prota@example.com"

以下のコマンドで、Gitリポジトリの作成・最初のコミットを実施します。

git init
git add .
git commit -m "First commit"

以降、まとまったコード追加・修正作業が終わったタイミングで、都度コミットしてバージョン管理しましょう。

Gitを使う理由や基本的な使い方に関しては、以下の記事も参考にしてください。

【C#、Blazor】Webアプリ開発入門編(3)Gitでバージョン管理 ~Gitの基本的な使い方を学ぶ~ 今回はWebアプリ開発を効率よく行う上で不可欠となる「バージョン管理ツールGit」について紹介します。 本記事では以下について、...

手順3:データモデル定義とDBへのマイグレーション

Todoリストアプリで使うデータモデルをC#クラスとして定義し、DBスキーマを生成(マイグレーション)します。

以下のように、ModelsフォルダとTodoItem.csをプロジェクトへ追加します。

TodoItem.csでは次のようにデータモデルであるTodoItemクラスを定義します。

using System.ComponentModel.DataAnnotations;

namespace TodoListApp.Models;

public class TodoItem
{
    [Key]
    public int Id { get; set; }
    public string Title { get; set; } = string.Empty;
}

[Key]という属性のついているフィールドが主キーとなります。

そして、Data/ApplicationDbContext.csへ以下のようにTodoItemsフィールドを追記しましょう。

…省略…

public class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : IdentityDbContext<ApplicationUser>(options)
{
    public DbSet<TodoItem> TodoItems { get; set; } //★ここを追記
}

EF Coreにおけるコードファーストのアプローチでは、「C#クラスによるデータモデル」が先にあり、そこから「DBスキーマ」を生成しDBへ反映します。

以下の2ステップでDBへ反映させます。

Step1,2を実行するためのツールをインストールします。

dotnet tool install --global dotnet-ef

次にTodoListApp.slnが存在するフォルダで以下のコマンドを実行し、Step1のマイグレーション用コード生成を行います。

dotnet ef migrations add AddTodoItem -o Data\Migrations

「AddTodoItem」の部分は変更内容がわかる好きな名前で大丈夫です。

Gitでいうところのコミット名みたいなものですね。

成功すると、以下のようにマイグレーション用コードが生成されます。

Step2としてコードを実行してマイグレーションをDBへ反映させましょう。

次のコマンドを実行します。

dotnet ef database update

特にエラーがなく、以下のような出力となれば成功です。

…省略…
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
      VALUES ('20240501080237_AddTodoItem', '8.0.4');
Done.

追加したTodoItemがDBスキーマとして反映されているか確認するため、DB Browser for SQLite等のツールでData/app.dbファイルの中身を覗いてみましょう。

DB Browser for SQLiteをWindowsへインストールする場合、こちらからダウンロードできます。

C#で定義したTodoItemクラスがDBテーブルTodoItemsとして定義されていますね!

プロ美

AspNetUsersとか、自分でクラス定義した覚えがないテーブルがたくさんあるよ?

プロ太

それは、このプロジェクトのひな型が「ASP.NET Core Identity」を使用しており、自動生成されたものですね。

「Data/Migrations/00000000000000_CreateIdentitySchema.cs」のマイグレーションコードが対応しています。

データモデルを修正・追加したときに、都度、このStep1(マイグレーションコード生成)、Step2(DBへの反映)を行います。

手順4:ServiceクラスでDB参照を実装

Todoリスト一覧を表示するため、TodoItemsテーブルからTodoの一覧を取得するビジネスロジックを実装します。

Servicesフォルダを作成し、以下のようにTodoListService.csを追加しましょう。

using Microsoft.EntityFrameworkCore;
using TodoListApp.Data;
using TodoListApp.Models;

namespace TodoListApp.Services;

public class TodoListService
{
    private readonly ApplicationDbContext _context;

    public TodoListService(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<List<TodoItem>> GetTodosAsync()
    {
        var items = await _context.TodoItems.ToListAsync();
        return items;
    }
}

TodoListServiceクラスはTodoリストに対する処理を行うビジネスロジックです。

今回の演習では一覧を参照して取得するGetTodosAsyncのみですが、今後更新の処理なども追加します。

EF Coreがこれらのメソッド呼び出しの裏側で、DB(今回はSQLite)へのSQLクエリを発行してくれています。

Program.csを修正して、「…builder.Build();」の前にAddScopedでTodoListServiceクラスをDI(Dpendency Injection)コンテナへ登録します。

…省略…
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();

builder.Services.AddScoped<TodoListService>(); //★ここを追記

var app = builder.Build();
…省略…

DIコンテナは、プログラムを構成する部品(クラスやオブジェクト)の関係性を自動的に管理してくれる仕組みです。

例えば、DIコンテナは以下のようなことを自動で行ってくれます。

今回でいうと、TodoListServiceクラスはApplicationDbContexクラスに依存しており、これらを以下のようにProgram.csでDIコンテナへ事前登録しています。

public class TodoListService
{
…省略…
    public TodoListService(ApplicationDbContext context)
    {
        _context = context;
    }
…省略…
…省略…
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(connectionString));
…省略…
builder.Services.AddScoped<TodoListService>(); 
…省略…

こうすることで、DIコンテナはTodoListServiceクラスのインスタンスを自動構築してくれます。

DIコンテナの役割や仕組みを理解するのは、最初は難しいかと思います。

まずは、なんとなくの雰囲気をつかんでもらえればOKです!

手順5:Todoリスト表示用のRazorコンポーネントを実装

Todoリスト表示のため、Compornents/PagesフォルダへTodoList.razorを追加します。

@page "/todolist"
@rendermode InteractiveServer
@using TodoListApp.Models
@using TodoListApp.Services
@inject TodoListService _todoService

<PageTitle>TodoList</PageTitle>

<h1>Todo List</h1>

<ul>
    @foreach (var item in _todoItems)
    {
        <li>
            <span>Id:@item.Id, @item.Title</span>
        </li>
    }
</ul>

@code {
    private List<TodoItem> _todoItems = new();

    protected override async Task OnInitializedAsync()
    {
        _todoItems = await _todoService.GetTodosAsync();
    }
}

Razorコンポーネントを使うとC#とHTMLを組み合わせてインタラクティブなWeb UIを構築できます。

Razorコンポーネントの主な構成要素と要点を簡単に説明します。

ディレクティブ

「@xxxx」の部分をディレクティブといいます。ディレクティブはRazorコンポーネントの振る舞いを指示する特別な構文です。上記コードでは以下が使われています。

  • @page "/todolist": このコンポーネントが “/todolist” というルートでアクセス可能なページであることを示します。
  • @rendermode InteractiveServer: コンポーネントがサーバー上でインタラクティブにレンダリングされる方式(Serverモード)と指定します。
  • @using: 必要な名前空間を指定し、コンポーネント内で使用するクラスにアクセス可能にします。
  • @inject: DIコンテナからTodoListServiceのインスタンスをコンポーネント内で利用できるように注入します。
HTML構造とRazor構文

コード内で<PageTitle><h1>などのHTMLタグを使ってUIを定義し、@foreach構文を使ってC#のコレクションをループ処理し、HTML内へのデータ埋め込みを行ってます。

これにより、動的なコンテンツの生成が簡単に行えます。

@codeブロック

@code ブロック内には、コンポーネントの状態を管理するためのC#コードを記述します。

上記コードでは、Todo項目リストを保持する_todoItemsフィールドを定義し、ページ初期化時に、DBからTodoリスト一覧を取得して代入しています。

最後に「Compornents/Layout/NavMenu.razor」へ、TodoList.razorページへのリンクを追加しておきます。

  …省略…
      <div class="nav-item px-3">
          <NavLink class="nav-link" href="weather">
              <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
          </NavLink>
      </div>

      @* ↓このリンクを追加 *@
      <div class="nav-item px-3">
          <NavLink class="nav-link" href="todolist">
              <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> TodoList
          </NavLink>
      </div>
      @* ↑このリンクを追加 *@

      <div class="nav-item px-3">
          <NavLink class="nav-link" href="auth">
              <span class="bi bi-lock-nav-menu" aria-hidden="true"></span> Auth Required
          </NavLink>
      </div>
 …省略…

アプリを実行

事前準備

プログラムを実行する前に、DBデータを事前準備しておきます。

アプリにはまだTodoを追加する機能がないため、DB Browser for SQLite等のツールでDBへ直接レコードを追加します。

DB Browser for SQLiteならば以下のような手順で、TodoItemsテーブルへ新規レコードを追加できます。

データ閲覧でTodoItemsテーブルを選び、レコード挿入ボタンを押してレコードを追加し、Titleに「掃除をする」などの値を設定します。Idは自動で割り振られます。

最後に「変更を書き込み」のボタンを押すとDBに変更が反映されます。

実行

Visual Studioでアプリをデバッグ実行し、TodoListのページをみると以下のように表示されます。

プロ美

DB参照してTodoリスト一覧を表示するところまでできたよ!

Blazorアプリ開発の第一歩ですね!

EF Coreを使ってCRUDのR部分(参照系)ができました!

まとめ

BlazorによるTodoリストアプリ作りの第一歩として、Todoリスト一覧を表示する機能を作りました。

EF Coreを使ったコードファーストの考え方やマイグレーションの方法を学びました。

また、Razorコンポーネントの基本的な使い方についても学びました。

次回は、DB更新系の方法について紹介し、Todoを削除・編集・追加できるようにします。また、Razorコンポーネントの再利用方法についても学んでいきます。

引き続き、Webアプリ開発とBlazorを一緒に学んでいきましょう!

ABOUT ME
プロ太
プログラミングを勉強している人へ情報を発信していきます! ・情報工学分野で博士(工学)の学位取得 ・言語:C# 、Java、C/C++、Python、JavaScript/TypeScript等 ・仕事は主に上流工程(WF開発・Agile開発、OSS開発経験あり) ・趣味で開発:3Dゲーム、Webアプリ、言語処理系等

ご依頼・ご相談について

プログラミング学習のご相談、お仕事のご依頼については、
こちらのお問い合わせページをご確認ください。