Try   HackMD
tags: .NET Core 3.1, MySQL, MVC, Synology, Docker

在 .NET Core 3.1 應用程式中整合 MySQL 資料庫

本文由 Grok AI 協助編輯

本文介紹如何在 .NET Core 3.1 應用程式中整合 MySQL 資料庫,延續前兩篇文章的 SimpleWeb 專案,並展示如何擴展功能以連線 MySQL 資料庫。本文假設讀者已熟悉第一篇的部署流程和第二篇的 Oracle 整合範例。我們將沿用第二篇的「書籍清單」範例,改用 MySQL 作為資料庫,並部署至 Synology NAS 的 Docker 環境。



實驗環境

  • NAS: RS3614RPxs, DS720P
  • DSM: 6.2.4-25556 Update 2
  • Windows 開發環境: .NET Core 3.1 SDK, Visual Studio 2019
  • 資料庫: MySQL(版本自定,假設運行於 NAS 或其他主機)

第一部分:應用程式擴展概述

在前兩篇文章中,我們部署了一個基本的 ASP.NET Core 3.1 MVC 應用程式並整合了 Oracle 資料庫。本文將使用相同的「書籍清單」功能:

  • 書籍管理:連線 MySQL 資料庫,查詢並展示書籍資料。

此功能將沿用第二篇的模型和視圖,僅更換資料庫為 MySQL。


第二部分:開發 MySQL 資料庫整合功能

步驟 1:安裝必要的 NuGet 套件

SimpleWeb 專案中,安裝以下套件:

  1. MySQL 支援
    • 安裝 MySql.Data.EntityFrameworkCore(版本與 .NET Core 3.1 相容,例如 8.0.22)。
  2. Entity Framework Core
    • 已安裝於第二篇(Microsoft.EntityFrameworkCore 3.1.10),無需重複安裝。

使用命令列:

dotnet add package MySql.Data.EntityFrameworkCore --version 8.0.22

步驟 2:定義模型與資料庫上下文

  1. 使用現有模型

    • 沿用第二篇的 Book.cs(位於 Models 資料夾):
      ​​​​​namespace SimpleWeb.Models
      ​​​​​{
      ​​​​​    public class Book
      ​​​​​    {
      ​​​​​        public int Id { get; set; }
      ​​​​​        public string Title { get; set; }
      ​​​​​        public string Author { get; set; }
      ​​​​​    }
      ​​​​​}
      
  2. 建立 MySqlDbContext

    • Data 資料夾中新增 MySqlDbContext.cs
      ​​​​​using Microsoft.EntityFrameworkCore;
      ​​​​​using SimpleWeb.Models;
      
      ​​​​​namespace SimpleWeb.Data
      ​​​​​{
      ​​​​​    public class MySqlDbContext : DbContext
      ​​​​​    {
      ​​​​​        public MySqlDbContext(DbContextOptions<MySqlDbContext> options) : base(options) { }
      
      ​​​​​        public DbSet<Book> Books { get; set; }
      ​​​​​    }
      ​​​​​}
      
    • 用途:與第二篇的 OracleDbContext 類似,MySqlDbContext 管理 MySQL 資料庫連線,DbSet<Book> 映射到 BOOKS 表格。

步驟 3:配置服務與連線字串

  1. 編輯 appsettings.json

    • 新增 MySQL 連線字串(可保留 Oracle 配置):
      ​​​​​{
      ​​​​​    "ConnectionStrings": {
      ​​​​​        "MySQL": "Server=<mysql_host>;Database=book_db;User=<user>;Password=<password>",
      ​​​​​        "Oracle": "User Id=<user>;Password=<password>;Data Source=<oracle_host>:<port>/<service_name>"
      ​​​​​    },
      ​​​​​    "Logging": {
      ​​​​​        "LogLevel": {
      ​​​​​            "Default": "Information",
      ​​​​​            "Microsoft": "Warning",
      ​​​​​            "Microsoft.Hosting.Lifetime": "Information"
      ​​​​​        }
      ​​​​​    },
      ​​​​​    "AllowedHosts": "*"
      ​​​​​}
      
    • 替換 <mysql_host><user><password>,例如:"Server=192.168.1.200;Database=book_db;User=root;Password=mypass"
  2. 編輯 Startup.cs

    • 註冊 MySQL 上下文:
      ​​​​​using SimpleWeb.Data;
      ​​​​​using Microsoft.EntityFrameworkCore;
      
      ​​​​​public void ConfigureServices(IServiceCollection services)
      ​​​​​{
      ​​​​​    services.AddControllersWithViews();
      
      ​​​​​    services.AddDbContext<MySqlDbContext>(options =>
      ​​​​​        options.UseMySql(Configuration.GetConnectionString("MySQL"), 
      ​​​​​            new MySqlServerVersion(new Version(8, 0, 22))));
      
      ​​​​​    services.AddDbContext<OracleDbContext>(options =>
      ​​​​​        options.UseOracle(Configuration.GetConnectionString("Oracle")));
      ​​​​​}
      

步驟 4:新增控制器與視圖

  1. 新增 BooksController
    • Controllers 資料夾中新增 BooksController.cs(與第二篇相同,僅更換上下文):
      ​​​​​using Microsoft.AspNetCore.Mvc;
      ​​​​​using SimpleWeb.Data;
      ​​​​​using SimpleWeb.Models;
      ​​​​​using System.Linq;
      
      ​​​​​namespace SimpleWeb.Controllers
      ​​​​​{
      ​​​​​    public class BooksController : Controller
      ​​​​​    {
      ​​​​​        private readonly MySqlDbContext _mySqlDbContext;
      
      ​​​​​        public BooksController(MySqlDbContext mySqlDbContext)
      ​​​​​        {
      ​​​​​            _mySqlDbContext = mySqlDbContext;
      ​​​​​        }
      
      ​​​​​        public IActionResult Index()
      ​​​​​        {
      ​​​​​            var books = _mySqlDbContext.Books.ToList();
      ​​​​​            return View(books);
      ​​​​​        }
      
      ​​​​​        [HttpPost]
      ​​​​​        public IActionResult Add(string title, string author)
      ​​​​​        {
      ​​​​​            var book = new Book { Title = title, Author = author };
      ​​​​​            _mySqlDbContext.Books.Add(book);
      ​​​​​            _mySqlDbContext.SaveChanges();
      ​​​​​            return RedirectToAction("Index");
      ​​​​​        }
      ​​​​​    }
      ​​​​​}
      
    • Views/Books 資料夾中新增 Index.cshtml(與第二篇相同):
      ​​​​​@model IEnumerable<SimpleWeb.Models.Book>
      
      ​​​​​<h2>Book List</h2>
      
      ​​​​​<form asp-action="Add" method="post">
      ​​​​​    <input name="title" placeholder="Book Title" />
      ​​​​​    <input name="author" placeholder="Author" />
      ​​​​​    <button type="submit">Add Book</button>
      ​​​​​</form>
      
      ​​​​​<table class="table">
      ​​​​​    <thead>
      ​​​​​        <tr>
      ​​​​​            <th>ID</th>
      ​​​​​            <th>Title</th>
      ​​​​​            <th>Author</th>
      ​​​​​        </tr>
      ​​​​​    </thead>
      ​​​​​    <tbody>
      ​​​​​        @foreach (var item in Model)
      ​​​​​        {
      ​​​​​            <tr>
      ​​​​​                <td>@item.Id</td>
      ​​​​​                <td>@item.Title</td>
      ​​​​​                <td>@item.Author</td>
      ​​​​​            </tr>
      ​​​​​        }
      ​​​​​    </tbody>
      ​​​​​</table>
      
模擬網頁輸出樣子

訪問 http://<NAS_IP>:62005/Books 時的模擬輸出(與第二篇一致):

Book List

[輸入框: Book Title] [輸入框: Author] [Add Book 按鈕]

ID | Title             | Author
-----------------------------------
1  | The Great Gatsby  | F. Scott Fitzgerald
2  | 1984              | George Orwell
3  | To Kill a Mockingbird | Harper Lee      (假設剛新增)
當「Add Book」按鈕按下後的程式運作
  1. 表單提交:使用者輸入標題(例如 "To Kill a Mockingbird")和作者(例如 "Harper Lee"),提交 POST 請求至 /Books/Add,資料為:title=To Kill a Mockingbird&author=Harper Lee
  2. 路由處理ASP.NET Core 導向 BooksController.Add
  3. 控制器執行
    • Add 方法接收 titleauthor,創建 Book 物件。
    • _mySqlDbContext.Books.Add(book) 標記為待新增。
    • _mySqlDbContext.SaveChanges() 執行 SQL:
      ​​​​​INSERT INTO BOOKS (TITLE, AUTHOR) VALUES ('To Kill a Mockingbird', 'Harper Lee');
      
    • MySQL 自動生成 ID,更新至 book.Id
    • 重新導向至 Index
  4. 頁面更新:顯示更新後的書籍清單。
模型綁定的說明
  • 機制ASP.NET Core 的模型綁定將表單資料(titleauthor)映射到 Add 方法的參數。表單中 <input name="title"><input name="author">name 屬性必須與參數名稱一致。
  • 範例:若改為 string titleName, string authorName,表單需調整為:
    ​​<input name="titleName" placeholder="Book Title" />
    ​​<input name="authorName" placeholder="Author" />
    

第三部分:更新 Dockerfile

MySQL 不需額外依賴,沿用簡化版 Dockerfile:

FROM mcr.microsoft.com/dotnet/aspnet:3.1 AS base
WORKDIR /app
EXPOSE 80

# 設置時區
ENV TZ=Asia/Taipei
RUN apt-get update && apt-get install -y tzdata
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 預設命令
ENTRYPOINT ["dotnet"]
  • 說明:移除第二篇的 libaio1NLS_LANG,因為 MySQL 不需這些依賴。

重新建構映像

執行 /volume1/docker/dotnet-runtime/build.sh 更新映像。


第四部分:部署流程

步驟 1:初始化 MySQL 資料庫

在 MySQL 上建立表格:

CREATE DATABASE book_db;
USE book_db;
CREATE TABLE BOOKS (
    ID INT AUTO_INCREMENT PRIMARY KEY,
    TITLE VARCHAR(255),
    AUTHOR VARCHAR(255)
);
  • 測試資料(可選):
    ​​INSERT INTO BOOKS (TITLE, AUTHOR) VALUES ('The Great Gatsby', 'F. Scott Fitzgerald');
    ​​INSERT INTO BOOKS (TITLE, AUTHOR) VALUES ('1984', 'George Orwell');
    

步驟 2:發佈與部署

  • 與第二篇相同,發佈至 /volume1/docker/mywebapp/

步驟 3:配置環境變數(可選)

  • 在 Docker 容器中新增:
    • 變數:ConnectionStrings__MySQL
    • 值:Server=<mysql_host>;Database=book_db;User=<user>;Password=<password>

步驟 4:啟動容器

  • 端口 62005,卷冊映射至 /app,命令為 dotnet /app/SimpleWeb.dll

步驟 5:驗證部署

  • 訪問 http://<NAS_IP>:62005/Books,新增書籍並確認資料儲存至 MySQL。

第五部分:修復常見問題

  1. MySQL 連線失敗
    • 檢查連線字串是否正確。
    • 確保 MySQL 允許遠端連線。
  2. 資料未顯示
    • 確認表格名稱與 MySqlDbContext 映射一致。

結論

本文展示了如何在 .NET Core 3.1 應用程式中整合 MySQL 資料庫,與 Oracle 整合相比,MySQL 配置更簡單,無需額外容器依賴。讀者可根據需求選擇適用的資料庫。