0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ASP.NET Core MVC 記載まとめ 【初学者編】1

Last updated at Posted at 2024-10-05

はじめに

ASP.NET Core MVCのプロジェクトを作成し、
データベース(MySQL)へ接続する機能を備えたRazor Pagesアプリケーションを構築します。


前回の記事はこちら


前提条件

XAMPP のインストール:以下のサイト様等をご参考ください。
XAMPP のインストール方法


MySQL の設定:以下のサイト様等をご参考ください。
SQL のインストールと設定


データベースの作成:以下のサイト様等をご参考ください。

データベース作成方法


※標準設定にてXAMPPにて、MySQLをインストールしてる場合

コマンドプロンプト(cmd)での操作

Windowsのスタートメニューを開き、「cmd」と入力してEnterを押します。

1.mysqlのあるディレクトリ内へ移動

cd C:\xampp\mysql\bin

2.MySQLに接続

mysql -u root -p

3.データベースの作成

CREATE DATABASE productdb;

① プロジェクトの作成

1.1・・・ Visual Studio インストールとワークロードの選択

 1. Visual Studio Installerを起動し、以下のワークロードを選択します。
   ●  ASP.NET と Web 開発
      : Webアプリケーション開発用
        ASP.NET Core などのフレームワークを使用して
        Webアプリケーションを開発します。

   ●  .NET デスクトップ開発
      : デスクトップアプリケーション開発を補助する機能
        Entity Frameworkなどのデスクトップアプリケーションの
        機能を利用するために追加します。

 2. 個別のコンポーネント選択
   ●「.NET SDK」
      : プロジェクトが .NET Core をターゲットにしています。

   ●「.NET 8.0 ランタイム(長期サポート)」
      : 最新の .NET バージョンをサポートするために選びます。

 3. プロジェクトの種類を選択
   ● Visual Studio の「新規プロジェクト」ウィンドウで、「ASP.NET Core Web アプリ」を選択します。
   
   ● フレームワークのバージョン: .NET 8 を選択
   
   ● 「認証なし」を選択します。これによりユーザー認証機能が自動的に含まれません。

   ● 「MVC」を選択し、Model-View-Controllerを使用したWebアプリケーションを作成します。

 4. プロジェクト名の設定
   ● プロジェクト名を「ProductsApp」に設定し、「場所」を「C:\temp\ASP.NET」に指定します。
 ※ 認証なしの特徴
   ●  ユーザー認証機能がない
      - ログインやユーザー登録のページ が作成されません。
      - ASP.NET Identity(ASP.NETのユーザー認証と管理システム)も含まれません。

   ●  アクセス制限がない
     - [Authorize] 属性などによるアクセス制御が設定されません。誰でもページにアクセスできます。

   ●  外部認証機能なし
     - GoogleやFacebookなどのOAuthやフォーム認証は設定されていません。必要に応じて後で手動で追加する必要があります。


1.2・・・フォルダ構成

/ProductsApp
├── Pages
│   ├── Products    //フォルダを新規作成
│       ├── Index.cshtml   //全ての製品の一覧を表示します。
│       ├── Create.cshtml  //新しい製品の登録を行います。
│       ├── Edit.cshtml    //既存の製品情報の編集を行います。
│       ├── Delete.cshtml  //製品の削除を行います。
│       ├── Details.cshtml //特定の製品の詳細を表示します。
│       ├── Index.cshtml.cs     // 製品一覧ページのモデル
│       ├── Create.cshtml.cs    // 新しい製品作成ページのモデル
│       ├── Edit.cshtml.cs      // 製品編集ページのモデル
│       ├── Delete.cshtml.cs    // 製品削除ページのモデル
│       ├── Details.cshtml.cs   // 製品詳細ページのモデル
│
├── Models    //フォルダを新規作成
│   ├── Product.cs                 //エンティティクラス
│   ├── ApplicationDbContext.cs    //DbContextクラス
│

② データベース接続設定

2.1・・・ データベース接続設定 (appsettings.json)

appsettings.json にMySQLを使用するための接続文字列を設定

接続文字列の例:
   ●  server: データベースサーバーのホスト名 (通常は localhost)
   ●  port: MySQLが使用するポート番号 (デフォルトは 3306)
   ●  database: 使用するデータベース名 (productdb など)
   ●  userid: MySQLで使用するユーザー名 (root など)
   ●  password: MySQLユーザーのパスワード
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "ProductContext": "Server=127.0.0.1;Port=3306;Database=productdb;Uid=root;Pwd=;"
  }
}



{
  "ConnectionStrings": {
    "ProductContext": "server=127.0.0.1;port=3306;database=productdb;userid=root;password="
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}


2.3・・・ モデル (Models/Product.cs)

製品情報をデータベースにマッピングします。

using System.ComponentModel.DataAnnotations;

namespace ProductsApp.Models
{
    // Productクラスは製品のデータ構造を表します
    public class Product
    {
        // ID プロパティ(プライマリキー)
        public int Id { get; set; }

        // 製品名は必須で最大100文字
        [Required]
        [StringLength(100)]
        public string Name { get; set; }

        // 製品の価格、必須
        [Required]
        public decimal Price { get; set; }

        // 製品の説明、必須ではない
        public string Description { get; set; }
    }
}

2.2・・・ DbContext クラスの作成 (Models/ApplicationDbContext.cs)

ソリューションエクスプローラーでプロジェクト名を右クリックし、
「追加」>「新しいフォルダー」を選択します。
フォルダー名を「Models」にします。

DbContext を継承し、データベースの接続と操作を管理するクラスを作成します。

using Microsoft.EntityFrameworkCore;

namespace ProductsApp.Models
{
    // ProductContextは、製品データベースとのやり取りを管理するDbContextクラスです。
    public class ProductContext : DbContext
    {
        // コンストラクタでDbContextOptionsを受け取り、親クラスに渡す
        public ProductContext(DbContextOptions<ProductContext> options) : base(options)
        {
        }

        // Productsテーブルを表すDbSet。製品データが格納される場所。
        public DbSet<Product> Products { get; set; }
    }
}

2.2・・・ パッケージがインストール

2.2.1. Visual Studio の「ソリューション エクスプローラー」でプロジェクトを右クリックし、「NuGet パッケージの管理」を選択します。

2.2.2. 「参照」タブで、以下のパッケージを検索してインストールします。

   ●  Pomelo.EntityFrameworkCore.MySql
   ●  Microsoft.EntityFrameworkCore.Tools

2.3・・・ 接続処理の実装手順 (Program.cs)

データベース接続の設定を追加し、アプリケーション起動時にMySQLへ接続できるように、コンテキストを追加します。

using Microsoft.EntityFrameworkCore;
using ProductsApp.Models;  // データベースコンテキストの名前空間

var builder = WebApplication.CreateBuilder(args);

// MySQL用のDbContextを登録
builder.Services.AddDbContext<ProductContext>(options =>
    options.UseMySql(
        builder.Configuration.GetConnectionString("ProductContext"),
        // MariaDB 10.4.32バージョンを指定
        new MySqlServerVersion(new Version(10, 4, 32))
    )
);

// MVC を使うためのサービスを登録
builder.Services.AddControllersWithViews();

// Razor Pagesのサービスを追加
builder.Services.AddRazorPages();  // ここを追加

var app = builder.Build();

// ミドルウェアの設定
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

// HTTPS へのリダイレクトと静的ファイルの提供
app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

// Razor Pagesのルート設定
app.MapRazorPages();

// ルートアクセス時のリダイレクト
app.MapGet("/", () => Results.Redirect("/Products"));

app.Run();

③ CRUD機能の自動生成

4.1 マイグレーションの実行
パッケージマネージャーコンソールを開き、次のコマンドを実行します。

4.1.1. マイグレーションの有効化

Add-Migration InitialCreate

4.1.2. データベースの更新

Update-Database
  • マイグレーションを実行すると、テーブルがデータベースに作成され、データの操作が可能になります

⑤ Razorページモデルの構成

「Pagesフォルダー」を右クリックし、
「追加」>「新しいフォルダー」を選択します。

フォルダー名を「Products」にします。

それぞれのRazorページモデルのビューと
ビハインドファイル(モデル)を作成します。


5.1.1. Index.cshtml.cs

using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using ProductsApp.Models;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ProductsApp.Pages.Products
{
    // IndexModelはすべての製品データをデータベースから取得し、表示するページモデル
    public class IndexModel : PageModel
    {
        private readonly ProductContext _context;

        // 製品リストを格納するためのプロパティ
        public IList<Product> Products { get; set; }

        // コンストラクタでデータベースコンテキストを注入
        public IndexModel(ProductContext context)
        {
            _context = context;
        }

        // 非同期メソッドでデータベースから製品情報を取得
        public async Task OnGetAsync()
        {
            Products = await _context.Products.ToListAsync();
        }
    }
}

5.1.2. Index.cshtml

@page
@model ProductsApp.Pages.Products.IndexModel

<!-- 製品のリストを表示するための見出し -->
<h1>製品一覧</h1>

<!-- 製品が存在する場合、リストを表示 -->
@if (Model.Products.Count > 0)
{
    <table class="table">
        <thead>
            <tr>
                <th>名前</th>
                <th>価格</th>
                <th>アクション</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var product in Model.Products)
            {
                <tr>
                    <td>@product.Name</td>
                    <td>@product.Price.ToString("C")</td>
                    <td>
                        <!-- 編集ページへのリンク -->
                        <a asp-page="Edit" asp-route-id="@product.Id">編集</a> |
                        <!-- 削除ページへのリンク -->
                        <a asp-page="Delete" asp-route-id="@product.Id">削除</a> |
                        <!-- 詳細ページへのリンク -->
                        <a asp-page="Details" asp-route-id="@product.Id">詳細</a>
                    </td>
                </tr>
            }
        </tbody>
    </table>
}
else
{
    <p>製品が見つかりませんでした。</p>
}

<!-- 新規作成ページへのリンク -->
<a asp-page="Create">新しい製品を作成</a>

5.2.1. Create.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using ProductsApp.Models;
using System.Threading.Tasks;

namespace ProductsApp.Pages.Products
{
    // CreateModelは新しい製品を作成するためのページモデル
    public class CreateModel : PageModel
    {
        private readonly ProductContext _context;

        // 製品の作成フォームをバインドするためのプロパティ
        [BindProperty]
        public Product Product { get; set; }

        // コンストラクタでデータベースコンテキストを注入
        public CreateModel(ProductContext context)
        {
            _context = context;
        }

        // Postメソッドで新しい製品をデータベースに追加
        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _context.Products.Add(Product);
            await _context.SaveChangesAsync();

            return RedirectToPage("./Index");
        }
    }
}

5.2.2. Create.cshtml

@page
@model ProductsApp.Pages.Products.CreateModel

<h1>製品の作成</h1>

<!-- 製品作成フォーム -->
<form method="post">
    <div>
        <label asp-for="Product.Name"></label>
        <input asp-for="Product.Name" />
        <span asp-validation-for="Product.Name"></span>
    </div>
    <div>
        <label asp-for="Product.Price"></label>
        <input asp-for="Product.Price" />
        <span asp-validation-for="Product.Price"></span>
    </div>
    <button type="submit">作成</button>
    <a asp-page="Index">戻る</a>
</form>

<!-- フォームのバリデーション用スクリプト -->
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}


5.3.1. Edit.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using ProductsApp.Models;
using System.Threading.Tasks;

namespace ProductsApp.Pages.Products
{
    // EditModelは既存の製品を編集するためのページモデル
    public class EditModel : PageModel
    {
        private readonly ProductContext _context;

        // 編集対象の製品をバインドするためのプロパティ
        [BindProperty]
        public Product Product { get; set; }

        // コンストラクタでデータベースコンテキストを注入
        public EditModel(ProductContext context)
        {
            _context = context;
        }

        // 指定されたIDに基づいて製品を取得
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            Product = await _context.Products.FirstOrDefaultAsync(m => m.Id == id);

            if (Product == null)
            {
                return NotFound();
            }
            return Page();
        }

        // Postメソッドで変更をデータベースに保存
        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _context.Attach(Product).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!ProductExists(Product.Id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return RedirectToPage("./Index");
        }

        // 製品が存在するかを確認するメソッド
        private bool ProductExists(int id)
        {
            return _context.Products.Any(e => e.Id == id);
        }
    }
}

5.3.2. Edit.cshtml

@page
@model ProductsApp.Pages.Products.EditModel

<h1>製品の編集</h1>

<form method="post">
    <input type="hidden" asp-for="Product.Id" /> <!-- IDを隠しフィールドとして追加 -->

    <div>
        <label asp-for="Product.Name"></label>
        <input asp-for="Product.Name" />
        <span asp-validation-for="Product.Name"></span>
    </div>
    <div>
        <label asp-for="Product.Price"></label>
        <input asp-for="Product.Price" />
        <span asp-validation-for="Product.Price"></span>
    </div>
    <div>
        <label asp-for="Product.Description"></label>
        <input asp-for="Product.Description" />
        <span asp-validation-for="Product.Description"></span>
    </div>
    <button type="submit">保存</button>
    <a asp-page="Index">戻る</a>
</form>

@section Scripts {
    @{
        await Html.RenderPartialAsync("_ValidationScriptsPartial");
    }
}

5.4.1. Delete.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using ProductsApp.Models;
using System.Threading.Tasks;

namespace ProductsApp.Pages.Products
{
    // DeleteModelは既存の製品を削除するためのページモデル
    public class DeleteModel : PageModel
    {
        private readonly ProductContext _context;

        // 削除対象の製品をバインドするためのプロパティ
        [BindProperty]
        public Product Product { get; set; }

        // コンストラクタでデータベースコンテキストを注入
        public DeleteModel(ProductContext context)
        {
            _context = context;
        }

        // 指定されたIDに基づいて製品を取得
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            Product = await _context.Products.FirstOrDefaultAsync(m => m.Id == id);

            if (Product == null)
            {
                return NotFound();
            }
            return Page();
        }

        // Postメソッドで製品を削除
        public async Task<IActionResult> OnPostAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            Product = await _context.Products.FindAsync(id);

            if (Product != null)
            {
                _context.Products.Remove(Product);
                await _context.SaveChangesAsync();
            }

            return RedirectToPage("./Index");
        }
    }
}

5.4.2. Delete.cshtml

@page
@model ProductsApp.Pages.Products.DeleteModel

<h1>製品の削除</h1>

<!-- 削除確認メッセージ -->
<h3>製品を削除しますか?</h3>
<div>
    <h4>製品名: @Model.Product.Name</h4>
    <p>価格: @Model.Product.Price.ToString("C")</p>
</div>

<!-- 削除確認フォーム -->
<form method="post">
    <button type="submit">削除</button>
    <a asp-page="Index">キャンセル</a>
</form>

5.5.1. Details.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using ProductsApp.Models;
using System.Threading.Tasks;

namespace ProductsApp.Pages.Products
{
    // DetailsModelは特定の製品の詳細を表示するためのページモデル
    public class DetailsModel : PageModel
    {
        private readonly ProductContext _context;

        // 表示する製品をバインドするためのプロパティ
        public Product Product { get; set; }

        // コンストラクタでデータベースコンテキストを注入
        public DetailsModel(ProductContext context)
        {
            _context = context;
        }

        // 指定されたIDに基づいて製品を取得
        public async Task<IActionResult> OnGetAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            Product = await _context.Products.FirstOrDefaultAsync(m => m.Id == id);

            if (Product == null)
            {
                return NotFound();
            }
            return Page();
        }
    }
}

5.4.2. Details.cshtml

@page
@model ProductsApp.Pages.Products.DetailsModel

<h1>製品の詳細</h1>

<!-- 製品情報の表示 -->
<div>
    <h4>製品名: @Model.Product.Name</h4>
    <p>価格: @Model.Product.Price.ToString("C")</p>
</div>

<!-- 戻るボタン -->
<a asp-page="Index">戻る</a>
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?