一.概述
HTTP不僅僅用于提供網(wǎng)頁。HTTP也是構(gòu)建公開服務和數(shù)據(jù)的API強大平臺。HTTP簡單靈活且無處不在。幾乎任何你能想到的平臺都有一個HTTP庫,因此HTTP服務可以覆蓋廣泛的客戶端,包括瀏覽器,移動設(shè)備和傳統(tǒng)的桌面應用程序。
ASP.NET Web API 是一個框架,基于.NET Framework 或.NET Core 之上構(gòu)建 Web API。
從本章開始學習Web API系列時,先從一個示例開始,下面使用ASP.NET Core MVC 創(chuàng)建 Web API。通過本次演示將了解到一個基礎(chǔ)的Web API應用。環(huán)境使用vs 2017 +sql server 2012。示例主要知識點包括:
(1)創(chuàng)建 Web API 項目。
(2)添加模型類。
(3)創(chuàng)建數(shù)據(jù)庫上下文。
(4)注冊數(shù)據(jù)庫上下文。
(5)添加控制器。
(6)添加 CRUD 方法。
(7)配置路由和 URL 路徑。
(8)指定返回值。
(9)使用Fiddle調(diào)用 Web API。
(10)使用 jQuery 調(diào)用 Web API。
在開發(fā)Web API之前,先制定幾個有針對性的API 接口,至于api 接口業(yè)務很簡單,主要是演示如何應用Web API。
| API接口 | 說明 | 請求報文 | 響應報文 |
|---|---|---|---|
| GET /api/todo | 獲取所有待辦事項 | 無 | 待辦事項的數(shù)據(jù) |
| GET /api/todo/{id} | 按 ID 獲取項 | 無 | 待辦事項 |
| POST /api/todo | 添加新項 | 待辦事項 | 待辦事項 |
| PUT /api/todo/{id} | 更新現(xiàn)有項 | 待辦事項 | 無 |
| DELETE /api/todo/{id} | 刪除項 | 無 | 無 |
1.1 創(chuàng)建web項目
(1)從“文件”菜單中選擇“新建” > “項目”。
(2)選擇“ASP.NET Core Web 應用程序”模板。 將項目命名為 TodoApi,然后單擊“確定”。
(3)在“新建 ASP.NET Core Web 應用程序 - TodoApi”對話框中,選擇 ASP.NET Core 版本。 選擇“API”模板,然后單擊“確定”。 請不要選擇“啟用 Docker 支持”。
項目模板會創(chuàng)建 values API。 控制器方法中默認的Http[Verb] 屬性路由包括GET,POST, PUT, DELETE接口
1.2 添加模型類
在項目中,添加Models文件夾,新建一個 TodoItem 類,如下所示:
public class TodoItem
{
//主鍵
public long Id { get; set; }
//待辦事項名稱
public string Name { get; set; }
//是否完成
public bool IsComplete { get; set; }
}
1.3 添加數(shù)據(jù)庫上下文
在“Models”文件夾,然后選擇“添加” > “類”。 將類命名為 TodoContext,如下所示:
//using Microsoft.EntityFrameworkCore;
public class TodoContext: DbContext
{
public TodoContext(DbContextOptions<TodoContext> options)
: base(options)
{
}
public DbSet<TodoItem> TodoItems { get; set; }
}
1.4 注冊上下文
在 ASP.NET Core 中,服務(如數(shù)據(jù)庫上下文)必須向依賴關(guān)系注入 (DI) 容器進行注冊。 該容器向控制器提供服務。這里使用Microsoft.EntityFrameworkCore.SqlServer數(shù)據(jù)提供程序。再根據(jù)模型生成數(shù)據(jù)庫表(庫名Todo,有一個表TodoItem)。關(guān)于如何安裝數(shù)據(jù)提供程序,以及如何用模型生成數(shù)據(jù)庫表,請參考“asp.net core 系列第 20 篇” 。使用遷移生成數(shù)據(jù)庫后,如下所示:

1.5 添加控制器
在Controllers 文件夾中,選擇“API 控制器類”模板。將類命名為 TodoController.cs, 代碼如下所示:
[Route("api/[controller]")]
[ApiController]//添加特性,代表是一個Web API控制器類
public class TodoController : Controller
{
private readonly TodoContext _context;
/// <summary>
/// 實例化一個EF上下文,進行數(shù)據(jù)庫操作。開始初始入庫一條數(shù)據(jù)
/// </summary>
/// <param name="context"></param>
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();
}
}
}
1.6 添加GET方法
通過GET方法來查詢待辦事項的 API,將以下方法添加到 TodoController 類中。關(guān)于路由知識,請參考asp.net core 系列第5篇。
/// <summary>
/// 獲取所有事項
/// GET: api/Todo
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
{
//using Microsoft.EntityFrameworkCore;
return await _context.TodoItems.ToListAsync();
}
/// <summary>
/// 根據(jù)id,獲取一條事項
/// GET: api/Todo/5。 id 是參數(shù),代表路由合并
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
return todoItem;
}
啟動vs,測試結(jié)果,如下所示,注意請求wep api 地址與action的方法名沒有關(guān)系,是根據(jù)方法名之上的Http[Verb]特性來確定url地址的:

1.7 路由和URL路徑
(1) Route特性
Route是用來制定路由模板的,在第5章中也講到。[Route("api/[controller]")]中是以api開頭,替換[controller] 為控制器的名稱, 按照慣例,控制器類名稱減去“Controller”后綴, 因此控制器名稱為“todo” ,路由不區(qū)分大小寫。
(2) HttpGet
如果[HttpGet]屬性具有路徑模板,例如:[HttpGet("{id}")], 則將其附加到路徑(如:api/todo/1)。在這個示例中, "{id}"是占位符變量,用于待辦事項的唯一標識符。
1.8 返回值
上面的GetTodoItems和GetTodoItem方法的返回類型是ActionResult <T>類型。ASP.NET Core自動將對象序列化為JSON,并將JSON寫入響應消息的正文中。假設(shè)沒有異常,此返回類型的響應代碼為200。未處理的異常被轉(zhuǎn)換為5xx錯誤。
ActionResult返回類型可以表示各種HTTP狀態(tài)代碼,例如在上面的GetTodoItem方法中可以返回兩個不同的狀態(tài)值:一個是成功的200, 一個是404未到找。所有的HTTP狀態(tài)代碼可以在ControllerBase中找到,例如下圖中的Forbid() 是Http狀態(tài)碼403,NoContent()是Http 狀態(tài)碼204 。 等等

二.測試Web API
下面簡單使用Fiddler來測試一下增刪改增。先在本機vs 2017中啟動該項目,地址為http://localhost:62271。
2.1 查詢
在Fiddler工具中,選擇GET,輸入查詢的http地址,右邊是響應的http 狀態(tài)碼200, 以及查詢的json結(jié)構(gòu)對象。

2.2 新增
下面創(chuàng)建方法,添加以下 PostTodoItem 方法,在新增方法中調(diào)用了CreatedAtAction內(nèi)置方法,如果新增成功,則返回 HTTP 201 狀態(tài)代碼。HTTP 201是HTTP POST方法的標準響應,該方法在服務器上創(chuàng)建新資源。
//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);
}

2.3 修改
添加以下 PutTodoItem 方法, PutTodoItem 與 PostTodoItem 類似,但是使用的是 HTTP PUT。 響應是 204(無內(nèi)容)。 根據(jù) HTTP 規(guī)范,PUT 請求需要客戶端發(fā)送整個更新的實體,而不僅僅是更改。若要支持部分更新,請使用HttpPatch特性。
// PUT: api/Todo/1
[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem item)
{
if (id != item.Id)
{
//http 403
return BadRequest();
}
//當前傳過來的實體添加到上下文,并設(shè)置為修改
_context.Entry(item).State = EntityState.Modified;
await _context.SaveChangesAsync();
return NoContent();
}

2.4 刪除
// DELETE: api/Todo/2
[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();
}