教學課程:使用 ASP.NET Core 建立 Web APITutorial: Create a web API with ASP.NET Core

Rick AndersonMike Wasson 提供By Rick Anderson and Mike Wasson

本教學課程將教導您使用 ASP.NET Core 建立 Web API 的基本概念。This tutorial teaches the basics of building a web API with ASP.NET Core.

在本教學課程中,您將了解如何:In this tutorial, you learn how to:

  • 建立 Web API 專案。Create a web API project.
  • 新增模型類別。Add a model class.
  • 建立資料庫內容。Create the database context.
  • 註冊資料庫內容。Register the database context.
  • 新增控制器。Add a controller.
  • 新增 CRUD 方法。Add CRUD methods.
  • 設定路由和 URL 路徑。Configure routing and URL paths.
  • 指定傳回值。Specify return values.
  • 使用 Postman 呼叫 Web API。Call the web API with Postman.
  • 使用 jQuery 呼叫 Web API。Call the web API with jQuery.

結束時,您將會有一個可管理關聯式資料庫中所儲存「待辦事項」的 Web API。At the end, you have a web API that can manage "to-do" items stored in a relational database.

總覽Overview

本教學課程會建立以下 API:This tutorial creates the following API:

APIAPI 說明Description 要求本文Request body 回應本文Response body
GET /api/todoGET /api/todo 取得所有待辦事項Get all to-do items NoneNone 待辦事項的陣列Array of to-do items
GET /api/todo/{id}GET /api/todo/{id} 依識別碼取得項目Get an item by ID NoneNone 待辦事項To-do item
POST /api/todoPOST /api/todo 新增記錄Add a new item 待辦事項To-do item 待辦事項To-do item
PUT /api/todo/{id}PUT /api/todo/{id} 更新現有的項目  Update an existing item   待辦事項To-do item NoneNone
DELETE /api/todo/{id}    DELETE /api/todo/{id}     刪除項目    Delete an item     NoneNone NoneNone

下圖顯示應用程式的設計。The following diagram shows the design of the app.

左側方塊代表用戶端。

必要條件Prerequisites

建立 Web 專案Create a web project

  • 從 [檔案] 功能表選取 [新增] > [專案] 。From the File menu, select New > Project.
  • 選取 ASP.NET Core Web 應用程式範本,然後按一下 [下一步] 。Select the ASP.NET Core Web Application template and click Next.
  • 將專案命名為 TodoApi,然後按一下 [建立] 。Name the project TodoApi and click Create.
  • 在 [建立新的 ASP.NET Core Web 應用程式] 對話方塊中,確認選取 [.NET Core] 和 [ASP.NET Core 2.2] 。In the Create a new ASP.NET Core Web Application dialog, confirm that .NET Core and ASP.NET Core 2.2 are selected. 選取 API 範本,然後按一下 [建立] 。Select the API template and click Create. 選取 [Enable Docker Support] (啟用 Docker 支援) 。Don't select Enable Docker Support.

VS 新增專案對話方塊

測試 APITest the API

專案範本會建立 values API。The project template creates a values API. 從瀏覽器呼叫 Get 方法來測試應用程式。Call the Get method from a browser to test the app.

按 Ctrl+F5 執行應用程式。Press Ctrl+F5 to run the app. Visual Studio 會啟動瀏覽器並巡覽至 https://localhost:<port>/api/values,其中 <port> 是隨機選擇的通訊埠編號。Visual Studio launches a browser and navigates to https://localhost:<port>/api/values, where <port> is a randomly chosen port number.

如果出現對話方塊詢問您是否應該信任 IIS Express 憑證,請選取 [是] 。If you get a dialog box that asks if you should trust the IIS Express certificate, select Yes. 在接著出現的 [安全性警告] 對話方塊中,選取 [是] 。In the Security Warning dialog that appears next, select Yes.

即會傳回下列 JSON:The following JSON is returned:

["value1","value2"]

新增模型類別Add a model class

「模型」 是代表應用程式所管理資料的一組類別。A model is a set of classes that represent the data that the app manages. 此應用程式的模型是單一 TodoItem 類別。The model for this app is a single TodoItem class.

  • 在 [方案總管] 中,以滑鼠右鍵按一下專案。In Solution Explorer, right-click the project. 選取 [新增] > [新增資料夾] 。Select Add > New Folder. 將資料夾命名為 ModelsName the folder Models.

  • 以滑鼠右鍵按一下 Models 資料夾,然後選取 [新增] > [類別] 。Right-click the Models folder and select Add > Class. 將類別命名為 TodoItem,然後選取 [新增] 。Name the class TodoItem and select Add.

  • 使用下列程式碼取代範本程式碼:Replace the template code with the following code:

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}

Id 屬性的功能相當於關聯式資料庫中的唯一索引鍵。The Id property functions as the unique key in a relational database.

模型類別可位於專案中的任何位置,但依照慣例會使用 Models 資料夾。Model classes can go anywhere in the project, but the Models folder is used by convention.

新增資料庫內容Add a database context

「資料庫內容」 是為資料模型協調 Entity Framework 功能的主要類別。The database context is the main class that coordinates Entity Framework functionality for a data model. 此類別是透過衍生自 Microsoft.EntityFrameworkCore.DbContext 類別來建立。This class is created by deriving from the Microsoft.EntityFrameworkCore.DbContext class.

  • 以滑鼠右鍵按一下 Models 資料夾,然後選取 [新增] > [類別] 。Right-click the Models folder and select Add > Class. 將類別命名為 TodoContext,然後按一下 [新增] 。Name the class TodoContext and click Add.
  • 使用下列程式碼取代範本程式碼:Replace the template code with the following code:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models
    {
        public class TodoContext : DbContext
        {
            public TodoContext(DbContextOptions<TodoContext> options)
                : base(options)
            {
            }
    
            public DbSet<TodoItem> TodoItems { get; set; }
        }
    }
    

登錄資料庫內容Register the database context

在 ASP.NET Core 中,資料庫內容等服務必須向相依性插入 (DI) 容器註冊。In ASP.NET Core, services such as the DB context must be registered with the dependency injection (DI) container. 此容器會將服務提供給控制器。The container provides the service to controllers.

使用下列醒目提示的程式碼更新 Startup.csUpdate Startup.cs with the following highlighted code:

// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using TodoApi.Models;

namespace TodoApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the 
        //container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<TodoContext>(opt =>
                opt.UseInMemoryDatabase("TodoList"));
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP 
        //request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for 
                // production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseMvc();
        }
    }
}

上述程式碼:The preceding code:

  • 移除未使用的 using 宣告。Removes unused using declarations.
  • 將資料庫內容新增至 DI 容器。Adds the database context to the DI container.
  • 指定資料庫內容將會使用記憶體內部資料庫。Specifies that the database context will use an in-memory database.

新增控制器Add a controller

  • 以滑鼠右鍵按一下 Controllers 資料夾。Right-click the Controllers folder.

  • 選取 [新增] > [新增項目] 。Select Add > New Item.

  • 在 [新增項目] 對話方塊中,選取 [API 控制器類別] 範本。In the Add New Item dialog, select the API Controller Class template.

  • 將類別命名為 TodoController,然後選取 [新增] 。Name the class TodoController, and select Add.

    在搜尋方塊中輸入 controller 且已選取 Web API 控制器的 [新增項目] 對話方塊

  • 使用下列程式碼取代範本程式碼:Replace the template code with the following code:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.EntityFrameworkCore;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using TodoApi.Models;
    
    namespace TodoApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class TodoController : ControllerBase
        {
            private readonly TodoContext _context;
    
            public TodoController(TodoContext context)
            {
                _context = context;
    
                if (_context.TodoItems.Count() == 0)
                {
                    // Create a new TodoItem if collection is empty,
                    // which means you can't delete all TodoItems.
                    _context.TodoItems.Add(new TodoItem { Name = "Item1" });
                    _context.SaveChanges();
                }
            }
        }
    }
    

上述程式碼:The preceding code:

  • 定義不含方法的 API 控制器類別。Defines an API controller class without methods.
  • 使用 [ApiController] 屬性來裝飾類別。Decorates the class with the [ApiController] attribute. 這個屬性表示控制器會回應 Web API 要求。This attribute indicates that the controller responds to web API requests. 如需屬性所啟用之特定行為的相關資訊,請參閱 使用 ASP.NET Core 建立 Web APIFor information about specific behaviors that the attribute enables, see 使用 ASP.NET Core 建立 Web API.
  • 使用 DI 將資料庫內容 (TodoContext) 插入到控制器中。Uses DI to inject the database context (TodoContext) into the controller. 控制器中的每一個 CRUD 方法都會使用資料庫內容。The database context is used in each of the CRUD methods in the controller.
  • 如果資料庫是空的,請將名為 Item1 的項目新增至資料庫。Adds an item named Item1 to the database if the database is empty. 此程式碼是在建構函式中,因此每次執行都會有新的 HTTP 要求。This code is in the constructor, so it runs every time there's a new HTTP request. 如果您刪除所有項目,則建構函式會在下次呼叫 API 方法時重新建立 Item1If you delete all items, the constructor creates Item1 again the next time an API method is called. 因此看起來雖然像是刪除失敗,但實際為成功。So it may look like the deletion didn't work when it actually did work.

新增 Get 方法Add Get methods

若要提供擷取待辦事項的 API,請在 TodoController 類別中新增下列方法:To provide an API that retrieves to-do items, add the following methods to the TodoController class:

// GET: api/Todo
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
{
    return await _context.TodoItems.ToListAsync();
}

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

這些方法會實作兩個 GET 端點:These methods implement two GET endpoints:

  • GET /api/todo
  • GET /api/todo/{id}

從瀏覽器呼叫這兩個端點來測試應用程式。Test the app by calling the two endpoints from a browser. 例如:For example:

  • https://localhost:<port>/api/todo
  • https://localhost:<port>/api/todo/1

以下是呼叫 GetTodoItems 所產生的 HTTP 回應:The following HTTP response is produced by the call to GetTodoItems:

[
  {
    "id": 1,
    "name": "Item1",
    "isComplete": false
  }
]

傳送和 URL 路徑Routing and URL paths

[HttpGet] 屬性代表回應 HTTP GET 要求的方法。The [HttpGet] attribute denotes a method that responds to an HTTP GET request. 每個方法的 URL 路徑的建構方式如下:The URL path for each method is constructed as follows:

  • 一開始在控制器的 Route 屬性中使用範本字串:Start with the template string in the controller's Route attribute:

    namespace TodoApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class TodoController : ControllerBase
        {
            private readonly TodoContext _context;
    
  • 以控制器的名稱取代 [controller],也就是將控制器類別名稱減去 "Controller" 字尾。Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. 在此範例中,控制器類別名稱是 TodoController,因此容器名稱是 "todo"。For this sample, the controller class name is TodoController, so the controller name is "todo". ASP.NET Core 路由不區分大小寫。ASP.NET Core routing is case insensitive.

  • 如果 [HttpGet] 屬性具有路由範本 (例如 [HttpGet("products")]),請將其附加到路徑。If the [HttpGet] attribute has a route template (for example, [HttpGet("products")]), append that to the path. 此範例不使用範本。This sample doesn't use a template. 如需詳細資訊,請參閱使用 Http[Verb] 屬性的屬性路由For more information, see Attribute routing with Http[Verb] attributes.

在下列 GetTodoItem 方法中,"{id}" 是待辦事項唯一識別碼的預留位置變數。In the following GetTodoItem method, "{id}" is a placeholder variable for the unique identifier of the to-do item. 在叫用 GetTodoItem 時,會將 URL 中的 "{id}" 值提供給方法的 id 參數。When GetTodoItem is invoked, the value of "{id}" in the URL is provided to the method in itsid parameter.

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

傳回值Return values

GetTodoItemsGetTodoItem 方法的傳回型別為 ActionResult<T> 類型The return type of the GetTodoItems and GetTodoItem methods is ActionResult<T> type. ASP.NET Core 會自動將物件序列化為 JSON,並將 JSON 寫入至回應訊息的本文。ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. 此傳回型別的回應碼為 200,假設沒有任何未處理的例外狀況。The response code for this return type is 200, assuming there are no unhandled exceptions. 未處理的例外狀況會轉譯成 5xx 錯誤。Unhandled exceptions are translated into 5xx errors.

ActionResult 傳回型別可代表各種 HTTP 狀態碼。ActionResult return types can represent a wide range of HTTP status codes. 例如,GetTodoItem 可傳回兩個不同的狀態值:For example, GetTodoItem can return two different status values:

  • 如果沒有項目符合所要求的識別碼,方法會傳回 404 NotFound 錯誤碼。If no item matches the requested ID, the method returns a 404 NotFound error code.
  • 否則,方法會傳回 200 與 JSON 回應本文。Otherwise, the method returns 200 with a JSON response body. 傳回 item 會導致 HTTP 200 回應。Returning item results in an HTTP 200 response.

測試 GetTodoItems 方法Test the GetTodoItems method

本教學課程使用 Postman 來測試 Web API。This tutorial uses Postman to test the web API.

  • 安裝 PostmanInstall Postman

  • 啟動 Web 應用程式。Start the web app.

  • 啟動 Postman。Start Postman.

  • 停用 [SSL certificate verification] (SSL 憑證驗證) Disable SSL certificate verification

    • 從 [檔案] > [設定] (* [一般] 索引標籤),停用 [SSL certificate verification] (SSL 憑證驗證) 。From File > Settings (*General tab), disable SSL certificate verification.

      警告

      在測試控制器之後,請重新啟用 [SSL certificate verification] (SSL 憑證驗證)。Re-enable SSL certificate verification after testing the controller.

  • 建立新的要求。Create a new request.

    • 將 HTTP 方法設定為 GETSet the HTTP method to GET.
    • 將要求 URL 設定為 https://localhost:<port>/api/todoSet the request URL to https://localhost:<port>/api/todo. 例如,https://localhost:5001/api/todoFor example, https://localhost:5001/api/todo.
  • 在 Postman 中,設定 [Two pane view] (雙窗格檢視) 。Set Two pane view in Postman.

  • 選取 [傳送] 。Select Send.

Postman 與 GET 要求

新增 Create 方法Add a Create method

新增以下 PostTodoItem 方法:Add the following PostTodoItem method:

// POST: api/Todo
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem item)
{
    _context.TodoItems.Add(item);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item);
}

上述程式碼是 HTTP POST 方法,如 [HttpPost] 屬性所示。The preceding code is an HTTP POST method, as indicated by the [HttpPost] attribute. 該方法會從 HTTP 要求本文取得待辦事項的值。The method gets the value of the to-do item from the body of the HTTP request.

CreatedAtAction 方法:The CreatedAtAction method:

  • 成功時會傳回 HTTP 201 狀態碼。Returns an HTTP 201 status code, if successful. 對於可在伺服器上建立新資源的 HTTP POST 方法,其標準回應是 HTTP 201。HTTP 201 is the standard response for an HTTP POST method that creates a new resource on the server.

  • Location 標頭加到回應中。Adds a Location header to the response. Location 標頭指定新建立之待辦事項的 URI。The Location header specifies the URI of the newly created to-do item. 如需詳細資訊,請參閱 10.2.2 201 Created (已建立 10.2.2 201)。For more information, see 10.2.2 201 Created.

  • 參考 GetTodoItem 動作以建立 Location 標頭的 URI。References the GetTodoItem action to create the Location header's URI. C# nameof 關鍵字是用來避免在 CreatedAtAction 呼叫中以硬式編碼方式寫入動作名稱。The C# nameof keyword is used to avoid hard-coding the action name in the CreatedAtAction call.

    // GET: api/Todo/5
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);
    
        if (todoItem == null)
        {
            return NotFound();
        }
    
        return todoItem;
    }
    

測試 PostTodoItem 方法Test the PostTodoItem method

  • 建置專案。Build the project.

  • 在 Postman 中,將 HTTP 方法設定為 POSTIn Postman, set the HTTP method to POST.

  • 選取 [本文] 索引標籤。Select the Body tab.

  • 選取 [原始] 選項按鈕。Select the raw radio button.

  • 將類型設定為 JSON (application/json)Set the type to JSON (application/json).

  • 在要求本文中,針對待辦項目輸入 JSON:In the request body enter JSON for a to-do item:

    {
      "name":"walk dog",
      "isComplete":true
    }
    
  • 選取 [傳送] 。Select Send.

    Postman 與建立要求

    如果您收到 405「不允許的方法」錯誤,可能是由於新增 PostTodoItem 方法之後未編譯專案所導致。If you get a 405 Method Not Allowed error, it's probably the result of not compiling the project after adding the PostTodoItem method.

測試位置標頭 URITest the location header URI

  • 在 [回應] 窗格中選取 [標頭] 索引標籤。Select the Headers tab in the Response pane.

  • 複製 [位置] 標頭值:Copy the Location header value:

    Postman 主控台的 [標頭] 索引標籤

  • 將方法設定為 GET。Set the method to GET.

  • 貼上 URI (例如 https://localhost:5001/api/Todo/2)Paste the URI (for example, https://localhost:5001/api/Todo/2)

  • 選取 [傳送] 。Select Send.

新增 PutTodoItem 方法Add a PutTodoItem method

新增以下 PutTodoItem 方法:Add the following PutTodoItem method:

// PUT: api/Todo/5
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem item)
{
    if (id != item.Id)
    {
        return BadRequest();
    }

    _context.Entry(item).State = EntityState.Modified;
    await _context.SaveChangesAsync();

    return NoContent();
}

PutTodoItem 類似於 PostTodoItem,但是會使用 HTTP PUT。PutTodoItem is similar to PostTodoItem, except it uses HTTP PUT. 回應是 204 (No Content) (204 (沒有內容))。The response is 204 (No Content). 根據 HTTP 規格,PUT 要求需要用戶端傳送整個更新的實體,而不只是變更。According to the HTTP specification, a PUT request requires the client to send the entire updated entity, not just the changes. 若要支援部分更新,請使用 HTTP PATCHTo support partial updates, use HTTP PATCH.

如果在呼叫 PutTodoItem 時發生錯誤,請呼叫 GET 以確保資料庫中有項目。If you get an error calling PutTodoItem, call GET to ensure there's an item in the database.

測試 PutTodoItem 方法Test the PutTodoItem method

此範例使用在每次應用程式啟動都必須起始的記憶體內部資料庫。This sample uses an in-memory database that must be initialed each time the app is started. 資料庫中必須有項目,您才能進行 PUT 呼叫。There must be an item in the database before you make a PUT call. 在發出 PUT 呼叫之前,請先呼叫 GET 以確保資料庫中有項目。Call GET to insure there's an item in the database before making a PUT call.

更新識別碼為 1 的待辦事項,並將其名稱設定為 "feed fish":Update the to-do item that has id = 1 and set its name to "feed fish":

  {
    "ID":1,
    "name":"feed fish",
    "isComplete":true
  }

下圖顯示 Postman 更新:The following image shows the Postman update:

顯示「204 (沒有內容) 回應」的 Postman 主控台

新增 DeleteTodoItem 方法Add a DeleteTodoItem method

新增以下 DeleteTodoItem 方法:Add the following DeleteTodoItem method:

// DELETE: api/Todo/5
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

DeleteTodoItem 回應是 204 (No Content) (204 (沒有內容))。The DeleteTodoItem response is 204 (No Content).

測試 DeleteTodoItem 方法Test the DeleteTodoItem method

使用 Postman 刪除待辦事項:Use Postman to delete a to-do item:

  • 將方法設定為 DELETESet the method to DELETE.
  • 設定要刪除的物件 URI,例如 https://localhost:5001/api/todo/1Set the URI of the object to delete, for example https://localhost:5001/api/todo/1
  • 選取 [傳送] Select Send

範例應用程式可讓您刪除所有項目。The sample app allows you to delete all the items. 但刪除最後一個項目之後,模型類別建構函式會在下次呼叫 API 時建立新的項目。However, when the last item is deleted, a new one is created by the model class constructor the next time the API is called.

使用 jQuery 呼叫 APICall the API with jQuery

在本節中,將會新增 HTML 網頁,以使用 jQuery 來呼叫 Web API。In this section, an HTML page is added that uses jQuery to call the web api. jQuery 會起始要求,並使用來自 API 回應的詳細資料更新頁面。jQuery initiates the request and updates the page with the details from the API's response.

藉由使用下列反白顯示的程式碼更新 Startup.cs,來設定應用程式提供靜態檔案啟用預設檔案對應Configure the app to serve static files and enable default file mapping by updating Startup.cs with the following highlighted code:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        // The default HSTS value is 30 days. You may want to change this for 
        // production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseDefaultFiles();
    app.UseStaticFiles();
    app.UseHttpsRedirection();
    app.UseMvc();
}

在專案目錄中建立 wwwroot 資料夾。Create a wwwroot folder in the project directory.

將名為 index.html 的 HTML 檔案新增至 wwwroot 目錄。Add an HTML file named index.html to the wwwroot directory. 將其內容取代為下列標記:Replace its contents with the following markup:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>To-do CRUD</title>
    <style>
        input[type='submit'], button, [aria-label] {
            cursor: pointer;
        }

        #spoiler {
            display: none;
        }

        table {
            font-family: Arial, sans-serif;
            border: 1px solid;
            border-collapse: collapse;
        }

        th {
            background-color: #0066CC;
            color: white;
        }

        td {
            border: 1px solid;
            padding: 5px;
        }
    </style>
</head>
<body>
    <h1>To-do CRUD</h1>
    <h3>Add</h3>
    <form action="javascript:void(0);" method="POST" onsubmit="addItem()">
        <input type="text" id="add-name" placeholder="New to-do">
        <input type="submit" value="Add">
    </form>

    <div id="spoiler">
        <h3>Edit</h3>
        <form class="my-form">
            <input type="hidden" id="edit-id">
            <input type="checkbox" id="edit-isComplete">
            <input type="text" id="edit-name">
            <input type="submit" value="Save">
            <a onclick="closeInput()" aria-label="Close">&#10006;</a>
        </form>
    </div>

    <p id="counter"></p>

    <table>
        <tr>
            <th>Is Complete</th>
            <th>Name</th>
            <th></th>
            <th></th>
        </tr>
        <tbody id="todos"></tbody>
    </table>

    <script src="https://code.jquery.com/jquery-3.3.1.min.js"
            integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
            crossorigin="anonymous"></script>
    <script src="site.js"></script>
</body>
</html>

將名為 site.js 的 JavaScript 檔案新增至 wwwroot 目錄。Add a JavaScript file named site.js to the wwwroot directory. 將其內容取代為下列程式碼:Replace its contents with the following code:

const uri = "api/todo";
let todos = null;
function getCount(data) {
  const el = $("#counter");
  let name = "to-do";
  if (data) {
    if (data > 1) {
      name = "to-dos";
    }
    el.text(data + " " + name);
  } else {
    el.text("No " + name);
  }
}

$(document).ready(function() {
  getData();
});

function getData() {
  $.ajax({
    type: "GET",
    url: uri,
    cache: false,
    success: function(data) {
      const tBody = $("#todos");

      $(tBody).empty();

      getCount(data.length);

      $.each(data, function(key, item) {
        const tr = $("<tr></tr>")
          .append(
            $("<td></td>").append(
              $("<input/>", {
                type: "checkbox",
                disabled: true,
                checked: item.isComplete
              })
            )
          )
          .append($("<td></td>").text(item.name))
          .append(
            $("<td></td>").append(
              $("<button>Edit</button>").on("click", function() {
                editItem(item.id);
              })
            )
          )
          .append(
            $("<td></td>").append(
              $("<button>Delete</button>").on("click", function() {
                deleteItem(item.id);
              })
            )
          );

        tr.appendTo(tBody);
      });

      todos = data;
    }
  });
}

function addItem() {
  const item = {
    name: $("#add-name").val(),
    isComplete: false
  };

  $.ajax({
    type: "POST",
    accepts: "application/json",
    url: uri,
    contentType: "application/json",
    data: JSON.stringify(item),
    error: function(jqXHR, textStatus, errorThrown) {
      alert("Something went wrong!");
    },
    success: function(result) {
      getData();
      $("#add-name").val("");
    }
  });
}

function deleteItem(id) {
  $.ajax({
    url: uri + "/" + id,
    type: "DELETE",
    success: function(result) {
      getData();
    }
  });
}

function editItem(id) {
  $.each(todos, function(key, item) {
    if (item.id === id) {
      $("#edit-name").val(item.name);
      $("#edit-id").val(item.id);
      $("#edit-isComplete")[0].checked = item.isComplete;
    }
  });
  $("#spoiler").css({ display: "block" });
}

$(".my-form").on("submit", function() {
  const item = {
    name: $("#edit-name").val(),
    isComplete: $("#edit-isComplete").is(":checked"),
    id: $("#edit-id").val()
  };

  $.ajax({
    url: uri + "/" + $("#edit-id").val(),
    type: "PUT",
    accepts: "application/json",
    contentType: "application/json",
    data: JSON.stringify(item),
    success: function(result) {
      getData();
    }
  });

  closeInput();
  return false;
});

function closeInput() {
  $("#spoiler").css({ display: "none" });
}

若要在本機測試 HTML 網頁,可能需要變更 ASP.NET Core 專案的啟動設定:A change to the ASP.NET Core project's launch settings may be required to test the HTML page locally:

  • 開啟 Properties\launchSettings.jsonOpen Properties\launchSettings.json.
  • 移除 launchUrl 屬性,以強制應用程式於 index.html 處開啟 — 專案的預設檔案。Remove the launchUrl property to force the app to open at index.html—the project's default file.

您可以使用幾種方式來取得 jQuery。There are several ways to get jQuery. 在上述的程式碼片段中,從 CDN 載入程式庫。In the preceding snippet, the library is loaded from a CDN.

此範例會呼叫 API 的所有 CRUD 方法。This sample calls all of the CRUD methods of the API. 以下是關於呼叫 API 的說明。Following are explanations of the calls to the API.

取得待辦事項的清單Get a list of to-do items

JQuery ajax 函式會將 GET 要求傳送至 API,API 則會傳回代表待辦事項陣列的 JSON。The jQuery ajax function sends a GET request to the API, which returns JSON representing an array of to-do items. 如果要求成功,則會叫用 success 回呼函式。The success callback function is invoked if the request succeeds. 在回呼中,DOM 已使用待辦事項資訊進行更新。In the callback, the DOM is updated with the to-do information.

$(document).ready(function() {
  getData();
});

function getData() {
  $.ajax({
    type: "GET",
    url: uri,
    cache: false,
    success: function(data) {
      const tBody = $("#todos");

      $(tBody).empty();

      getCount(data.length);

      $.each(data, function(key, item) {
        const tr = $("<tr></tr>")
          .append(
            $("<td></td>").append(
              $("<input/>", {
                type: "checkbox",
                disabled: true,
                checked: item.isComplete
              })
            )
          )
          .append($("<td></td>").text(item.name))
          .append(
            $("<td></td>").append(
              $("<button>Edit</button>").on("click", function() {
                editItem(item.id);
              })
            )
          )
          .append(
            $("<td></td>").append(
              $("<button>Delete</button>").on("click", function() {
                deleteItem(item.id);
              })
            )
          );

        tr.appendTo(tBody);
      });

      todos = data;
    }
  });
}

新增待辦事項Add a to-do item

ajax 函式會傳送 POST 要求,並在要求本文中包含待辦事項。The ajax function sends a POST request with the to-do item in the request body. acceptscontentType 選項都設定為 application/json,以指定接收和傳送的媒體類型。The accepts and contentType options are set to application/json to specify the media type being received and sent. 待辦事項會使用 JSON.stringify 轉換成 JSON。The to-do item is converted to JSON by using JSON.stringify. 當 API 傳回成功狀態碼時,會叫用 getData 函式來更新 HTML 資料表。When the API returns a successful status code, the getData function is invoked to update the HTML table.

function addItem() {
  const item = {
    name: $("#add-name").val(),
    isComplete: false
  };

  $.ajax({
    type: "POST",
    accepts: "application/json",
    url: uri,
    contentType: "application/json",
    data: JSON.stringify(item),
    error: function(jqXHR, textStatus, errorThrown) {
      alert("Something went wrong!");
    },
    success: function(result) {
      getData();
      $("#add-name").val("");
    }
  });
}

更新待辦事項Update a to-do item

更新待辦事項類似於新增待辦事項。Updating a to-do item is similar to adding one. url 會變更為新增項目的唯一識別碼,而 typePUTThe url changes to add the unique identifier of the item, and the type is PUT.

$.ajax({
  url: uri + "/" + $("#edit-id").val(),
  type: "PUT",
  accepts: "application/json",
  contentType: "application/json",
  data: JSON.stringify(item),
  success: function(result) {
    getData();
  }
});

刪除待辦事項Delete a to-do item

刪除待辦事項的達成方法是將 AJAX 呼叫的 type 設定為 DELETE,並在 URL 中指定項目的唯一識別碼。Deleting a to-do item is accomplished by setting the type on the AJAX call to DELETE and specifying the item's unique identifier in the URL.

$.ajax({
  url: uri + "/" + id,
  type: "DELETE",
  success: function(result) {
    getData();
  }
});

其他資源Additional resources

檢視或下載本教學課程的範例程式碼View or download sample code for this tutorial. 請參閱如何下載See how to download.

如需詳細資訊,請參閱下列資源:For more information, see the following resources:

後續步驟Next steps

在本教學課程中,您將了解如何:In this tutorial, you learned how to:

  • 建立 Web API 專案。Create a web api project.
  • 新增模型類別。Add a model class.
  • 建立資料庫內容。Create the database context.
  • 註冊資料庫內容。Register the database context.
  • 新增控制器。Add a controller.
  • 新增 CRUD 方法。Add CRUD methods.
  • 設定路由和 URL 路徑。Configure routing and URL paths.
  • 指定傳回值。Specify return values.
  • 使用 Postman 呼叫 Web API。Call the web API with Postman.
  • 使用 jQuery 呼叫 Web API。Call the web api with jQuery.

前進到下一個教學課程來了解如何產生 API 說明頁面:Advance to the next tutorial to learn how to generate API help pages: