使用Scaffolding功能建立Web API - 2
.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N240826401
出刊日期: 2024/8/7
本篇文章將延續本站《使用Scaffolding功能建立Web API - 1》一文的情境,介紹如何使用Visual Studio 2022的Scaffolding功能建立Web API來開發ASP.NET Core Web API,利用工具的圖型介面進行資料移轉以及測試Web API。
管理連結服務
Visual Studio 2022現在內建管理連結服務的功能,從「Solution Explorer」視窗,專案名稱下的「Connected Services」項目上方按滑鼠右鍵,從快捷選單選擇「Manage Connected Services」項目,請參考下圖所示:
圖 1:「Manage Connected Services」項目。
使用資料移轉功能
接下來會開啟一個畫面,讓你選擇要連線的服務,點選「SQL Server Express LocalDb (Local)」右方的「...」按鈕,從快捷選單選擇「Add migration」項目,請參考下圖所示:
圖 2:「Add migration」項目。
接下來會看到「Entity Framework Migrations」視窗,要求取一個名稱,例如本例中的「Initial」,並選取「MyAPIDemoContext」類別,然後按下「Finish」按鈕,請參考下圖所示:
圖 3:「Entity Framework Migrations」視窗。
接下來按下「Entity Framework Migrations」視窗「Finish」按鈕,關閉「Entity Framework Migrations」視窗,請參考下圖所示:
圖 4:關閉「Entity Framework Migrations」視窗。
接著Visual Studio 2022會在專案中「Migrations」資料夾內,產生一個「xxx_ Initial.cs」檔案,描述即將要對資料庫結構的異動,請參考以下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | using System;using Microsoft.EntityFrameworkCore.Migrations;#nullable disablenamespace MyAPIDemo.Migrations{ /// <inheritdoc /> public partial class Initial : Migration { /// <inheritdoc /> protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "Book", columns: table => new { Id = table.Column<int>(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), Title = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false), Price = table.Column<int>(type: "int", nullable: false), PublishDate = table.Column<DateTime>(type: "datetime2", nullable: false), InStock = table.Column<bool>(type: "bit", nullable: false), Description = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true) }, constraints: table => { table.PrimaryKey("PK_Book", x => x.Id); }); } /// <inheritdoc /> protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "Book"); } }} |
此外專案根目錄下「MyAPIDemoContextModelSnapshot.cs」檔案內則包含了模型快照(Model Snapshot)程式碼,它記錄了資料庫模型的結構和配置。當你進行資料庫移轉時,Entity Framework Core 會根據這個模型快照來生成相應的 SQL 陳述句,以使資料庫的結構與應用程式的模型保持同步。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | // <auto-generated />using System;using Microsoft.EntityFrameworkCore;using Microsoft.EntityFrameworkCore.Infrastructure;using Microsoft.EntityFrameworkCore.Metadata;using Microsoft.EntityFrameworkCore.Storage.ValueConversion;using MyAPIDemo.Data;#nullable disablenamespace MyAPIDemo.Migrations{ [DbContext(typeof(MyAPIDemoContext))] partial class MyAPIDemoContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) {#pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "8.0.4") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("MyAPIDemo.Book", b => { b.Property<int>("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); b.Property<string>("Description") .HasMaxLength(50) .HasColumnType("nvarchar(50)"); b.Property<bool>("InStock") .HasColumnType("bit"); b.Property<int>("Price") .HasColumnType("int"); b.Property<DateTime>("PublishDate") .HasColumnType("datetime2"); b.Property<string>("Title") .IsRequired() .HasMaxLength(50) .HasColumnType("nvarchar(50)"); b.HasKey("Id"); b.ToTable("Book"); });#pragma warning restore 612, 618 } }} |
專案中的「XXX_Initial.Designer.cs」檔案也是工具自動生成的,給開發工具使用,參考以下程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | // <auto-generated />using System;using Microsoft.EntityFrameworkCore;using Microsoft.EntityFrameworkCore.Infrastructure;using Microsoft.EntityFrameworkCore.Metadata;using Microsoft.EntityFrameworkCore.Migrations;using Microsoft.EntityFrameworkCore.Storage.ValueConversion;using MyAPIDemo.Data;#nullable disablenamespace MyAPIDemo.Migrations{ [DbContext(typeof(MyAPIDemoContext))] [Migration("20240621074423_Initial")] partial class Initial { /// <inheritdoc /> protected override void BuildTargetModel(ModelBuilder modelBuilder) {#pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "8.0.4") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("MyAPIDemo.Book", b => { b.Property<int>("Id") .ValueGeneratedOnAdd() .HasColumnType("int"); SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); b.Property<string>("Description") .HasMaxLength(50) .HasColumnType("nvarchar(50)"); b.Property<bool>("InStock") .HasColumnType("bit"); b.Property<int>("Price") .HasColumnType("int"); b.Property<DateTime>("PublishDate") .HasColumnType("datetime2"); b.Property<string>("Title") .IsRequired() .HasMaxLength(50) .HasColumnType("nvarchar(50)"); b.HasKey("Id"); b.ToTable("Book"); });#pragma warning restore 612, 618 } }} |
更新資料庫
回到「Manage Connected Services」畫面,點選「SQL Server Express LocalDb (Local)」右方的「...」按鈕,從快捷選單選擇「Update database」項目以更新資料庫,請參考下圖所示:
圖 5: 更新資料庫。
下一步在「Entity Framework Migrations」視窗「DbContext class names」項目選取「MyAPIDemoContext」類別,然後按下「Finish」按鈕,請參考下圖所示:
圖 6:選取「MyAPIDemoContext」類別。
接下來按下「Entity Framework Migrations」視窗「Finish」按鈕,關閉「Entity Framework Migrations」視窗,請參考下圖所示:
圖 7:關閉「Entity Framework Migrations」視窗。
使用Swagger測試Web API
除了利用「MyAPIDemo.http」測試Web API的功能之外,預設專案也支援Swagger,只要執行網站,就會自動啟動瀏覽器,開啟Swagger UI讓你測試Web API,請參考下圖所示:
圖 8:使用Swagger測試Web API。
測試Web API功能
以下分別說明如何利用Swagger來測試Web API功能:
Post
使用Swagger送出HTTP Post請求,提供以下JSON格式的資料:
1 2 3 4 5 6 7 8 | { "id": 0, "title": "Programming", "price": 123, "publishDate": "2024-06-21", "inStock": true, "description": "Programming book"} |
執行結果請參考下圖所示:
圖 9:測試Post功能。
參考下圖是送出HTTP Post請求新增一筆「Book」資料的執行結果:
圖 10:新增一筆「Book」資料。
Get
參考下圖是使用Swagger測試頁面送出HTTP Get請求取回所有圖書資料的執行結果:
圖 11:取回所有圖書資料。
參考下圖是送出HTTP Get請求取回「id」為「1」的「Book」資料之執行結果:
圖 12:取回「id」為「1」的「Book」資料。
Put
送出HTTP Put請求時,我們提供以下JSON格式的資料來修改「id」為「1」的「Book」資料:
1 2 3 4 5 6 7 8 | { "id": 1, "title": "Programming Web API", "price": 1230, "publishDate": "2024-06-21", "inStock": true, "description": "Programming Web API book"} |
執行結果請參考下圖所示:
圖 13:送出HTTP Put請求。
當送出HTTP Put請求時,會得到一個500號例外錯誤,錯誤訊息如下:
Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot update identity column 'Id'.
at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
例外錯誤的資訊,請參考下圖所示:
圖 14:HTTP Put產生500號例外錯誤。
從錯誤訊息中得知,當進行修改動作時,不允許修改「id」,讓我們修改工具產生的「BookEndpoints.cs」程式碼,將「SetProperty(m => m.Id, book.Id)」這行程式刪除:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | group.MapPut("/{id}", async Task<Results<Ok, NotFound>> (int id, Book book, MyAPIDemoContext db) => { var affected = await db.Book .Where(model => model.Id == id) .ExecuteUpdateAsync(setters => setters .SetProperty(m => m.Id, book.Id) .SetProperty(m => m.Title, book.Title) .SetProperty(m => m.Price, book.Price) .SetProperty(m => m.PublishDate, book.PublishDate) .SetProperty(m => m.InStock, book.InStock) .SetProperty(m => m.Description, book.Description) ); return affected == 1 ? TypedResults.Ok() : TypedResults.NotFound(); }) .WithName("UpdateBook") .WithOpenApi(); |
目前「MapPut」方法的程式碼看起來如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | group.MapPut("/{id}", async Task<Results<Ok, NotFound>> (int id, Book book, MyAPIDemoContext db) => { var affected = await db.Book .Where(model => model.Id == id) .ExecuteUpdateAsync(setters => setters .SetProperty(m => m.Title, book.Title) .SetProperty(m => m.Price, book.Price) .SetProperty(m => m.PublishDate, book.PublishDate) .SetProperty(m => m.InStock, book.InStock) .SetProperty(m => m.Description, book.Description) ); return affected == 1 ? TypedResults.Ok() : TypedResults.NotFound(); }) .WithName("UpdateBook") .WithOpenApi(); |
完成之後,再使用Swagger測試,這次可以正確修改圖書資料,參考下圖是送出HTTP Put請求修改圖書資料的執行結果:
圖 15::Put請求執行結果。
Delete
參考下圖是送出HTTP Delete請求刪除「Book」資料的執行結果:
圖 16:送出HTTP Delete請求刪除圖書資料。
使用Endpoint explorer瀏覽與測試Web API
Visual Studio 2022還有一個小功能,能讓你很容易找尋、測試Web API端點。只要選取「View」>「Endpoints Explorer」開啟視窗,請參考下圖所示:
圖 17:開啟「Endpoints Explorer」視窗。
「Endpoints Explorer」視窗會自動偵測並列出中專案中的Web API端點,請參考下圖所示:
圖 18:自動偵測並列出中專案中的Web API端點。
你可以點選「Endpoints Explorer」視窗其中的請求項目,從快捷選單選擇「Generate Request」項目,就會自動開啟「*.http」檔案讓你進行測試,請參考下圖所示:
圖 19:「Generate Request」項目。
在開啟的「*.http」檔案中,會自動生成送出請求的指令,請參考以下程式碼:
1 2 3 4 5 6 7 8 9 10 | @MyAPIDemo_HostAddress = https://localhost:7005GET {{MyAPIDemo_HostAddress}}/weatherforecast/Accept: application/json###GET {{MyAPIDemo_HostAddress}}/api/Book/### |
接著便可以點選指令上方的「Send Request」連結進行測試,請參考下圖所示:
圖 20:測試Web API。





















0 意見:
張貼留言