ASP.NET Core MVC で 簡単なWebアプリを作成③

ASP.NET Core MVC で 簡単なWebアプリを作成③

目次

はじめに
Model の作成
Controller の内容を追加
View の内容を変更
DB との接続
次回予告

はじめに

本記事は、ASP.NET Core MVC を利用したWebアプリケーション開発について、勉強用兼備忘録として執筆しています。最終的に、簡単なWebアプリ(TODOアプリ)を作成することが目標になります。

前回は、実際に ASP.NET Core MVC でプロジェクトを作り、TODOアプリのモックを表示させるところまで行いました。

今回は、モックで決め打ちデータを表示していた部分をモデルを使用して画面上に表示できるように、モデルの追加・コントローラの変更・ビューの変更を行い、DB上にテーブル作成するまでを行いたいと思います!

Model の作成

では、早速モデルを作成していきます。
「Models」フォルダ―を右クリックし、「追加 > クラス」の順に選択して、「ToDoTask.cs」のファイルを作成します。

「Models/ToDotask.cs」ファイルの内容を、以下のコードに変更します。
プロパティは、モックで作成していた項目の内容と同一にします。

using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcApplication1.Models
{
    public class ToDoTask
    {
        // ID
        public int Id { get; set; }

        // 完了フラグ
        public bool isDone { get; set; }

        // プロジェクト名
        [Display(Name = "プロジェクト名")]
        [Required(ErrorMessage = "{0}は必須です")]
        [MaxLength(50, ErrorMessage = "{0}は{1}文字以下で入力してください")]
        public string ProjectName { get; set; } = string.Empty;

        // 内容
        [Display(Name = "内容")]
        [Required(ErrorMessage = "{0}は必須です")]
        [MaxLength(50, ErrorMessage = "{0}は{1}文字以下で入力してください")]
        public string TaskName { get; set; } = string.Empty;

        // 期限日
        [Display(Name = "期限日")]
        [DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}")]
        public string? DeadLine { get; set; } = string.Empty;

        // 登録日
        [Display(Name = "登録日")]
        [DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}")]
        public string? CreateDateTime { get; set; } = string.Empty;

        // 更新日
        [Display(Name="更新日")]
        [DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}")]
        public string? UpdateDateTime { get; set; } = string.Empty;
    }
}

ここでポイントとなるのが、 Id という名前のプロパティです。
後ほど登場してくる「 EntityFrameworkCore 」によって、Id または <type name>Id という名前のプロパティが自動的にエンティティの主キーとして判断され、数値型の場合は自動採番されるようになりますので、必ず設定しておきます。

Controller の内容を追加

では、画面側で先ほどのモデルが使用されるように、「Controller/HomeController.cs」の内容を以下のように変更します。

using Microsoft.AspNetCore.Mvc;
using MvcApplication1.Models;
using System;
using System.Diagnostics;

namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        private static List<ToDoTask> _toDoTask = new List<ToDoTask>()
        {
            new ToDoTask{ Id=1, isDone=true, ProjectName="■▲●プロジェクト", TaskName="〇〇システムの提案書作成", DeadLine="2023/10/31", CreateDateTime=DateTime.Now.ToString("yyyy/MM/dd") ,UpdateDateTime=DateTime.Now.ToString("yyyy/MM/dd")},
            new ToDoTask{ Id=2, isDone=false, ProjectName="ABCプロジェクト", TaskName="〇〇の見積作成", DeadLine="2023/11/10", CreateDateTime=DateTime.Now.ToString("yyyy/MM/dd") ,UpdateDateTime= DateTime.Now.ToString("yyyy/MM/dd")},
            new ToDoTask{ Id=3, isDone=false, ProjectName="〇△□プロジェクト", TaskName="〇〇システムの改修", DeadLine="2023/11/30", CreateDateTime=DateTime.Now.ToString("yyyy/MM/dd") ,UpdateDateTime= DateTime.Now.ToString("yyyy/MM/dd")},
        };

        public IActionResult Index()
        {
            return View(_toDoTask);
        }

        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }
        public IActionResult Privacy()
        {
            return View();
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}

この_toDoTask リストは、ToDoタスクのデータを一時的に格納し、 アプリケーション内で ToDoタスク情報を管理するために使用されます。
今回は、画面表示時に分かりやすいように、モックで表示していたものと同じ内容のサンプルデータを3つ含めました。
そして、画面表示時にサンプルデータ3つが表示されるように、Index()メゾットで作成した _toDoTask リストをビュー側に渡します。

View の内容を変更

では、ビュー側で、モデルの値を表示するように「Views\Home\Index.cshtml」の内容を以下のように変更します。

@model IEnumerable<MvcApplication1.Models.ToDoTask>

@{
    ViewData["Title"] = "Home Page";
}

<div>
    <div class="text-center my-sm-5">
        <h1>TODO リスト</h1>
    </div>
    <div style="margin-bottom:20px;">
        <div>
            <button type="button" class="btn btn-outline-primary">タスク追加</button>
        </div>
    </div>
</div>
<table class="table">
    <thead>
        <tr>
            <th>
            </th>
            <th>
                @Html.DisplayNameFor(model => model.ProjectName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.TaskName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.DeadLine)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.CreateDateTime)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.UpdateDateTime)
            </th>
            <th>
                編集・削除
            </th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    <input type="checkbox" class="form-check-input" @(item.isDone ? "checked" : "")>
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.ProjectName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.TaskName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.DeadLine)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.CreateDateTime)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.UpdateDateTime)
                </td>
                <td>
                    <button type="button" class="btn-primary">編集</button>
                    <button type="button" class="btn-secondary">削除</button>
                </td>
            </tr>
        }
    </tbody>
</table>
<div>
    <nav>
        <ul class="pagination justify-content-center">
            <li class="page-item">
                <a class="page-link" href="#"><</a>
            </li>
            <li class="page-item"><a class="page-link" href="#">1</a></li>
            <li class="page-item"><a class="page-link" href="#">2</a></li>
            <li class="page-item"><a class="page-link" href="#">3</a></li>
            <li class="page-item">
                <a class="page-link" href="#">></a>
            </li>
        </ul>
    </nav>
</div>

一番上の@model IEnumerable<MvcApplication1.Models.ToDoTask>では、ビューページに対するモデルの型を指定しています。
@foreach (var item in Model) { ... }で、ToDoTask のリストをループ処理します。Modelはビューに渡されたモデルデータで、itemは各ToDoタスクを表します。

では、一度画面を確認してみます。

_toDoTask リストに追加したサンプルモデル3つが表示されていることが分かります。モデルを使って画面側に表示できました!
では次に、DBとの接続ができるように設定していきたいと思います。

DBとの接続

DBを作成し、アプリと連携させるためには、下記の手順を踏む必要があります。

  • Nuget パッケージから Entity Framework Core をインストールする
  • コンテキストクラスを定義する
  • 依存性注入(Dependency Injection)
  • アプリ設定ファイルに接続文字列を追加
  • マイグレーションの作成・適用
  • DB を確認してみる

Nuget パッケージから Entity Framework Core をインストールする

今回は、データベースに PostgreSQL を使いたいと思います。
Nuget パッケージマネージャの管理画面から、「npgsql」で検索後、「Npgsql.EntityFrameworkCore.PostgresSQL」をインストールします。

「正常にインストールされました」と表示されていればインストール完了です。

コンテキストクラスを定義する

データモデルをデータベースに接続するように設定するのが、コンテキストクラスです。
コンテキストクラスを作成するため、 「Models」フォルダー配下に 「ToDoTaskContext.cs ファイルを作成します。

「ToDoTaskContext.csのコードの内容は以下の通りです。

using Microsoft.EntityFrameworkCore;

namespace MvcApplication1.Models
{
    public class TodoTaskContext :DbContext
    {
        public TodoTaskContext(DbContextOptions<TodoTaskContext> options) : base(options)
        {
        }
        public DbSet<ToDoTask> ToDoTask { get; set; }
    }
}

TodoTaskContext クラスのコンストラクターは、 ASP.NET Coreの依存性注入(Dependency Injection)を介してデータベース接続情報を設定します。
TodoTaskContext クラスでは、DBのテーブルとアプリケーションのモデルをマッピングし、 Entity Framework Core を使用して DB にクエリを実行しデータを取得、更新、削除することが可能となります。

依存性注入 (Dependency Injection)

先程話が出ましたが、ASP.NET Coreには、 Dependency Injection(DI) が組み込まれています。DI は、依存関係の管理に役立つ一般的なツールです。
「Program.cs」で、データベースコンテキストを DI に登録するように、下記を追加します。

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<TodoTaskContext>(options => options.UseNpgsql(connectionString));

1行目のconnectionStringは、データベース接続文字列を取得したものです。”DefaultConnection” は、アプリケーションの設定ファイル(appsettings.jsonなど)に定義されている接続文字列の名前です。
この取得したデータベース接続文字列を用いて、データベースとやり取りするための設定を2行目で行っています。

※ データベース接続文字列 ・・・ データベースに接続するために必要な情報を含んで いるもの

アプリ設定ファイルに接続文字列を追加

では、先程話があがった「接続文字列」を「appsettings.json」ファイルへ追加します。データベース接続情報は、自分の環境に合わせて設定します。

  "ConnectionStrings": {
    "DefaultConnection": "User Id=postgres;Password=password;Server=localhost;Database=MvcApplication1;Port=5432;Pooling=true;"
  },

マイグレーションの作成・適用

最後に、Entity Framework Core のマイグレーション機能を使用して、データベースを作成します。この機能によって、プログラム上で定義されたテーブル定義を、DBに移行させることが可能になります。

まず、コマンドが利用できるように、「Microsoft.EntityFrameworkCore.Tools」のパッケージをパッケージマネージャからインストールします。
インストール完了後、 パッケージ マネージャー コンソール 上で、以下のコマンドを入力します。

PM> Add-Migration InitialModels

「Build succeeded.」が表示されれば OK です。これは、”InitialModels”という名前のマイグレーションを作成しています。
続いて、Entity Framework Core プロジェクト内で定義されたマイグレーションをデータベースに適用するために、以下のコマンドを入力します。

PM> Update-Database

DB を確認してみる

では、実際に DB がアプリケーション内のモデルと同じ内容で作成されているか確認してみます。

PgAdmin で確認すると、確かに「MvcApplication1」というDBが作成されていることが分かります!
「ToDoTask」テーブルの中身を見てみると、Model で設定した通りにテーブル項目が作成されています。

次回予告

今回は 、 モックで決め打ちデータを表示していた部分をモデルを使用して画面上に表示できるように、モデルの追加・コントローラの変更・ビューの変更を行い、DB上にテーブル作成するまでを行いました。
次回は、 テーブルとの関連付けと ToDo タスクの「追加」「編集」「削除」ができるようにしたいと思います。