在本教程中,將生成用於管理“待辦事項”列表的 Web API。 不會生成 UI。
概述
以下是將創建的 API:
API | 描述 | 請求正文 | 響應正文 |
---|---|---|---|
GET /api/todo | 獲取所有待辦事項 | 無 | 待辦事項的數組 |
GET /api/todo/{id} | 按 ID 獲取項 | 無 | 待辦事項 |
POST /api/todo | 添加新項 | 待辦事項 | 待辦事項 |
PUT /api/todo/{id} | 更新現有項 | 待辦事項 | 無 |
DELETE /api/todo/{id} | 刪除項 | 無 | 無 |
下圖顯示了應用的基本設計。
-
客戶端使用的是 Web API(移動應用、瀏覽器等)。 在本教程中,我們不編寫客戶端, 而使用 Postman 或 curl 來測試應用。
-
模型是表示應用程序中的數據的對象。 在此示例中,唯一的模型是待辦事項。 模型表示為 C# 類,也稱為 Plain Old C# Object (POCO)。
-
控制器是處理 HTTP 請求並創建 HTTP 響應的對象。 此應用將有一個控制器。
-
為了簡化教程,應用不會使用永久數據庫。 示例應用將待辦事項存儲在內存數據庫中。
先決條件
安裝以下組件:
- .NET Core 2.0.0 SDK 或更高版本。
- 已安裝 ASP.NET 和 Web 開發工作負載的 Visual Studio 2017 15.3 版或更高版本。
請參閱此 PDF 了解有關 ASP.NET Core 1.1 版本的信息。
創建項目
在 Visual Studio 中,選擇“文件”菜單 >“新建” > “項目”。
選擇“ASP.NET Core Web 應用程序(.NET Core)”項目模板。 將此項目命名為 TodoApi
,然后選擇“確定”。
在“新建 ASP.NET Core Web 應用程序 - TodoApi”對話框中,選擇“Web API”模板。 選擇“確定”。 請不要選擇“啟用 Docker 支持”。
啟動應用
在 Visual Studio 中,按 CTRL+F5 啟動應用。 Visual Studio 啟動瀏覽器並導航到 http://localhost:port/api/values
,其中“端口”是隨機選擇的端口號。 Chrome、Edge 和 Firefox 將顯示以下內容:
["value1","value2"]
添加模型類
模型是表示應用程序中的數據的對象。 在此示例中,唯一的一個模型是待辦事項。
添加名為“Models”的文件夾。 在解決方案資源管理器中,右鍵單擊項目。 選擇“添加” > “新建文件夾”。 將文件夾命名為“Models”。
注意:模型類可位於項目的任意位置,但按照慣例會使用“Models”文件夾。
添加 TodoItem
類。 右鍵單擊“Models”文件夾,然后選擇“添加” > “類”。 將此類命名為 TodoItem
,然后選擇“添加”。
將生成的代碼替換為以下內容:
namespace TodoApi.Models { public class TodoItem { public long Id { get; set; } public string Name { get; set; } public bool IsComplete { get; set; } } }
創建 TodoItem
時,數據庫將生成 Id
。
創建數據庫上下文
數據庫上下文是為給定數據模型協調實體框架功能的主類。 此類由 Microsoft.EntityFrameworkCore.DbContext
類派生而來。
添加 TodoContext
類。 右鍵單擊“Models”文件夾,然后選擇“添加” > “類”。 將此類命名為 TodoContext
,然后選擇“添加”。
將生成的代碼替換為以下內容:
using Microsoft.EntityFrameworkCore; namespace TodoApi.Models { public class TodoContext : DbContext { public TodoContext(DbContextOptions<TodoContext> options) : base(options) { } public DbSet<TodoItem> TodoItems { get; set; } } }
注冊數據庫上下文
若要將數據庫上下文注入到控制器中,需要將它注冊到依賴關系注入容器。 使用依賴關系注入的內置支持將數據庫上下文注冊到服務容器。 使用以下內容替換 Startup.cs 文件的內容:
using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using TodoApi.Models; namespace TodoApi { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddDbContext<TodoContext>(opt => opt.UseInMemoryDatabase("TodoList")); services.AddMvc(); } public void Configure(IApplicationBuilder app) { app.UseMvc(); } } }
前面的代碼:
- 刪除未使用的代碼。
- 指定將內存數據庫注入到服務容器中。
添加控制器
在解決方案資源管理器中,右鍵單擊“控制器”文件夾。 選擇“添加” > “新建項”。 在“添加新項”對話框中,選擇“Web API 控制器類”模板。 將此類命名為 TodoController
。
將生成的代碼替換為以下內容:
using System.Collections.Generic; using Microsoft.AspNetCore.Mvc; using TodoApi.Models; using System.Linq; namespace TodoApi.Controllers { [Route("api/[controller]")] public class TodoController : Controller { private readonly TodoContext _context; public TodoController(TodoContext context) { _context = context; if (_context.TodoItems.Count() == 0) { _context.TodoItems.Add(new TodoItem { Name = "Item1" }); _context.SaveChanges(); } } } }
前面的代碼:
- 定義空控制器類。 在接下來的部分中,我們將添加方法來實現 API。
- 構造函數使用依賴關系注入將數據庫上下文 (
TodoContext
) 注入到控制器中。 數據庫上下文將在控制器中的每個 CRUD 方法中使用。 - 構造函數將一個項(如果不存在)添加到內存數據庫。
獲取待辦事項
若要獲取待辦事項,請將下面的方法添加到 TodoController
類中。
[HttpGet] public IEnumerable<TodoItem> GetAll() { return _context.TodoItems.ToList(); } [HttpGet("{id}", Name = "GetTodo")] public IActionResult GetById(long id) { var item = _context.TodoItems.FirstOrDefault(t => t.Id == id); if (item == null) { return NotFound(); } return new ObjectResult(item); }
這些方法實現兩種 GET 方法:
GET /api/todo
GET /api/todo/{id}
以下是 GetAll
方法的 HTTP 響應示例:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/10.0
Date: Thu, 18 Jun 2015 20:51:10 GMT
Content-Length: 82
[{"Key":"1", "Name":"Item1","IsComplete":false}]
稍后在本教程中將演示如何使用 Postman 或 curl 查看 HTTP 響應。
路由和 URL 路徑
[HttpGet]
特性指定 HTTP GET 方法。 每個方法的 URL 路徑構造如下所示:
- 在控制器的路由特性中采用模板字符串:
namespace TodoApi.Controllers { [Route("api/[controller]")] public class TodoController : Controller { private readonly TodoContext _context;
- 將“[Controller]”替換為控制器的名稱,即在控制器類名稱中去掉“Controller”后綴。 對於此示例,控制器類名稱為“Todo”控制器,根名稱為“todo”。 ASP.NET Core 路由不區分大小寫。
- 如果
[HttpGet]
特性具有路由模板(如[HttpGet("/products")]
),則將它追加到路徑。 此示例不使用模板。 有關詳細信息,請參閱使用 Http [Verb] 特性的特性路由。
在 GetById
方法中:
[HttpGet("{id}", Name = "GetTodo")] public IActionResult GetById(long id)
"{id}"
是 todo
項 的 ID 的占位符變量。 調用 GetById
時,它會將 URL 中“{id}”的值分配給方法的 id
參數。
Name = "GetTodo"
創建一個命名的路由,使你能夠 HTTP 響應中鏈接到此路由。 稍后將使用示例進行解釋。 有關詳細信息,請參閱路由到控制器操作。
返回值
GetAll
方法返回 IEnumerable
。 MVC 自動將對象序列化為 JSON,並將 JSON 寫入響應消息的正文中。 在假設沒有未經處理的異常的情況下,此方法的響應代碼為 200。 (未經處理的異常將轉換為 5xx 錯誤。)
相反,GetById
方法返回多個常規的 IActionResult
類型,它表示一系列返回類型。 GetById
具有兩個不同的返回類型:
-
如果沒有任何項與請求的 ID 匹配,此方法將返回 404 錯誤。 此通過返回
NotFound
來實現。 -
否則,此方法將返回具有 JSON 響應正文的 200。 此通過返回
ObjectResult
來完成
啟動應用
在 Visual Studio 中,按 CTRL+F5 啟動應用。 Visual Studio 啟動瀏覽器並導航到 http://localhost:port/api/values
,其中“端口”是隨機選擇的端口號。 如果使用的是 Chrome、Edge 或 Firefox,則會顯示數據。 如果使用的是 IE,IE 將提示你打開或保存 values.json 文件。 導航到剛剛創建的 Todo
控制器 http://localhost:port/api/todo
。
實現其他的 CRUD 操作
我們將向控制器添加 Create
、Update
和 Delete
方法。 這些是主題的變體,因此在這里只提供代碼並突出顯示主要的差異。 添加或更改代碼后生成項目。
創建
[HttpPost] public IActionResult Create([FromBody] TodoItem item) { if (item == null) { return BadRequest(); } _context.TodoItems.Add(item); _context.SaveChanges(); return CreatedAtRoute("GetTodo", new { id = item.Id }, item); }
這是 HTTP POST 方法,由 [HttpPost]
特性指示的。 [FromBody]
特性告訴 MVC 從 HTTP 請求正文獲取待辦事項的值。
CreatedAtRoute
方法返回 201 響應,這是在服務器上創建新資源的 HTTP POST 方法的標准響應。 CreatedAtRoute
還會向響應添加位置標頭。 位置標頭指定新建的待辦事項的 URI。 請參閱 10.2.2 201 已創建。
使用 Postman 發送創建請求
- 將 HTTP 方法設置為
POST
- 選擇“正文”單選按鈕
- 選擇“原始”單選按鈕
- 將類型設置為 JSON
- 在鍵值編輯器中,輸入一個待辦事項,例如
{
"name":"walk dog", "isComplete":true }
-
選擇“發送”
-
選擇下窗格中的“標頭”選項卡,然后復制“位置”標頭:
可以使用此位置標頭 URI 訪問剛剛創建的資源。 重新調用創建名為 "GetTodo"
路由時使用的 GetById
方法:
[HttpGet("{id}", Name = "GetTodo")] public IActionResult GetById(long id)
更新
[HttpPut("{id}")] public IActionResult Update(long id, [FromBody] TodoItem item) { if (item == null || item.Id != id) { return BadRequest(); } var todo = _context.TodoItems.FirstOrDefault(t => t.Id == id); if (todo == null) { return NotFound(); } todo.IsComplete = item.IsComplete; todo.Name = item.Name; _context.TodoItems.Update(todo); _context.SaveChanges(); return new NoContentResult(); }
Update
與 Create
類似,但是使用的是 HTTP PUT。 響應是 204(無內容)。 根據 HTTP 規范,PUT 請求需要客戶端發送整個更新的實體,而不僅僅是增量。 若要支持部分更新,請使用 HTTP PATCH。
刪除
[HttpDelete("{id}")] public IActionResult Delete(long id) { var todo = _context.TodoItems.FirstOrDefault(t => t.Id == id); if (todo == null) { return NotFound(); } _context.TodoItems.Remove(todo); _context.SaveChanges(); return new NoContentResult(); }
響應是 204(無內容)。