はじめに
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>