在本文中,我們將一起查看TodoController 類代碼。
[Route] 屬性定義了Controller的URL 模板:
[Route("api/[controller]")]
所有符合該模板類型的HTTP 請求都會被路由到該controller。在本例中, 路由的命名規范為對應Controller 的前綴,對於TodoController 類,路由模板為 “api/todo”。
HTTP 方法
[HttpGet]、[HttpPost]和[HttpDelete] 屬性定義為 controller 動作對應的HTTP 方法 (另外也有[HttpPut] 和 [HttpPatch] 屬性,在本示例中沒有使用。)
[HttpGet]
public IEnumerable<TodoItem> GetAll() {}
[HttpGet("{id:int}", Name = "GetByIdRoute")]
public IActionResult GetById (int id) {}
[HttpPost]
public void CreateTodoItem([FromBody] TodoItem item) {}
[HttpDelete("{id:int}")]
public IActionResult DeleteItem(int id) {}
GetById 和DeleteItem 方法中的參數可以增加路由的傳遞信息。所以,路由模板更加完善的寫法為“api/[controller]/{id:int}”。
在 “{id:int}” 中,id是變量,而 “:int” 代表參數為整型。以下為URLs實例:
http://localhost/api/todo/1
http://localhost/api/todo/42
不能寫為:
http://localhost/api/todo/abc
注意 GetById 和 DeleteItem 方法同樣擁有命名為id的參數。framework 會自動傳遞實參值到Controller中。例如,如果URL為http://localhost/api/todo/42,id的值則為42,這個過程為參數綁定。
CreateTodoItem 方法代表了另一個參數綁定:
[HttpPost]
public void CreateTodoItem([FromBody] TodoItem item) {}
[FromBody] 屬性指定framework 從Request中反序列化TodoItem 參數。
以下是request和controller 動作的對應列表:
Request |
Controller Action |
GET /api/todo |
GetAll |
POST /api/todo |
CreateTodoItem |
GET /api/todo/1 |
GetById |
DELETE /api/todo/1 |
DeleteItem |
GET /api/todo/abc |
none – returns 404 |
PUT /api/todo |
none – returns 404 |
最后兩個例子由於其他用途返回404 錯誤。例如 'GET /api/todo/abc', 'abc' 實參是GetById 方法中要求的整型數據類型。
Action 返回值
TodoController 類展示了多種 controller action的返回值方法。
GetAll 方法返回了一個CLR 對象。
[HttpGet]
public IEnumerable<TodoItem> GetAll()
{
return _items;
}
返回對象的序列化信息被存儲到Response消息中。默認格式為JSON,客戶端同樣可以接收XML數據格式:
GET http://localhost:5000/api/todo HTTP/1.1
User-Agent: Fiddler
Host: localhost:5000
Accept: application/xml
Response:
HTTP/1.1 200 OK
Content-Type: application/xml;charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 30 Oct 2014 22:40:10 GMT
Content-Length: 228
<ArrayOfTodoItem xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/TodoApi.Models"><TodoItem><Id>1</Id><IsDone>false</IsDone><Title>First Item</Title></TodoItem></ArrayOfTodoItem>
GetById 方法返回了一個IActionResult 接口:
[HttpGet("{id:int}", Name = "GetByIdRoute")]
public IActionResult GetById (int id)
{
var item = _items.FirstOrDefault(x => x.Id == id);
if (item == null)
{
return HttpNotFound();
}
return new ObjectResult(item);
}
如果有URL中對應的id,則這個方法會返回ObjectResult 。返回 ObjectResult 和返回CLR 模型相同。而方法中規定返回類型為IActionResult。因此,該方法可以返回不同的類型。
如果沒有對應ID,則返回HttpNotFound,頁面會拋出404 錯誤。
最后, CreateTodoItem 方法展示如何直接在方法中設置返回值:
[HttpPost]
public void CreateTodoItem([FromBody] TodoItem item)
{
// (some code not shown here)
Context.Response.StatusCode = 201;
Context.Response.Headers["Location"] = url;
}
這種方法的缺陷是很難進行單元測試。(關於測試相關討論,可以參考Unit Testing Controllers in ASP.NET Web API)。
依賴注入
MVC 6 內置了依賴注入功能。下面,讓我們創建一個包含ToDo列表的repository 類。
首先,為repository定義一個接口:
using System.Collections.Generic;
namespace TodoApi.Models
{
public interface ITodoRepository
{
IEnumerable<TodoItem> AllItems { get; }
void Add(TodoItem item);
TodoItem GetById(int id);
bool TryDelete(int id);
}
}
之后定義具體實現方法。
using System;
using System.Collections.Generic;
using System.Linq;
namespace TodoApi.Models
{
public class TodoRepository : ITodoRepository
{
readonly List<TodoItem> _items = new List<TodoItem>();
public IEnumerable<TodoItem> AllItems
{
get
{
return _items;
}
}
public TodoItem GetById(int id)
{
return _items.FirstOrDefault(x => x.Id == id);
}
public void Add(TodoItem item)
{
item.Id = 1 + _items.Max(x => (int?)x.Id) ?? 0;
_items.Add(item);
}
public bool TryDelete(int id)
{
var item = GetById(id);
if (item == null)
{
return false;
}
_items.Remove(item);
return true;
}
}
}
使用構造函數注入repository 到 controller:
[Route("api/[controller]")]
public class TodoController : Controller
{
// Remove this code:
//static readonly List<TodoItem> _items = new List<TodoItem>()
//{
// new TodoItem { Id = 1, Title = "First Item" }
//};
// Add this code:
private readonly ITodoRepository _repository;
public TodoController(ITodoRepository repository)
{
_repository = repository;
}
然后更新controller 方法到repository:
[HttpGet]
public IEnumerable<TodoItem> GetAll()
{
return _repository.AllItems;
}
[HttpGet("{id:int}", Name = "GetByIdRoute")]
public IActionResult GetById(int id)
{
var item = _repository.GetById(id);
if (item == null)
{
return HttpNotFound();
}
return new ObjectResult(item);
}
[HttpPost]
public void CreateTodoItem([FromBody] TodoItem item)
{
if (!ModelState.IsValid)
{
Context.Response.StatusCode = 400;
}
else
{
_repository.Add(item);
string url = Url.RouteUrl("GetByIdRoute", new { id = item.Id }, Request.Scheme, Request.Host.ToUriComponent());
Context.Response.StatusCode = 201;
Context.Response.Headers["Location"] = url;
}
}
[HttpDelete("{id}")]
public IActionResult DeleteItem(int id)
{
if (_repository.TryDelete(id))
{
return new HttpStatusCodeResult(204); // 201 No Content
}
else
{
return HttpNotFound();
}
}
我們需要注冊repository到依賴注入系統才能使其啟作用。在Startup 類中,添加以下代碼:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// New code
services.AddSingleton<ITodoRepository, TodoRepository>();
}
應用運行時, 一旦controller被創建,framework 自動注入TodoRepository 到controller中,它將作用於整個應用的生命周期。
在IIS外獨立部署應用
默認情況下,當你點擊F5,應用會在IIS Express中運行。你可以在工具欄中看到IIS Express 圖標。
ASP.NET 5.0 可以部署到不同的服務器中,在本節中,我們將使用可運行在IIS外的WebListener。
注意:將應用部署在IIS中仍有諸多的優勢,例如安全性、進度管理等。
在project.json 文件,添加Microsoft.AspNet.Server.WebListener 包:
"dependencies": {
"Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
"Microsoft.AspNet.Diagnostics": "1.0.0-beta1",
"Microsoft.AspNet.Mvc": "6.0.0-beta1",
// New:
"Microsoft.AspNet.Server.WebListener": "6.0.0-beta1"
},
接下來添加以下選項到project.json。
{
// Other sections not shown
"commands": {
"web ": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
}
}
“commands” 中包含了可以傳遞給K 運行時的預定義指令列表。在這個例子中, “web” 是指令名稱,它可以是任意實際指令名稱值。
Microsoft.AspNet.Hosting 程序集用於部署ASP.NET 5.0 應用。
· --server 標記用於聲明服務器,在這個例子中為WebListener。
· --server.urls 標記提供需要監聽的URL。
保存project.json 文件。在Solution Explorer中,右鍵點擊工程選擇Properties。在 Properties 欄,點擊Debug。在Debug target 下,更改 “IIS Express” 為 “web”。
點擊F5運行App。Visual Studio 這時會運行啟動WebListener 的控制台應用。
打開瀏覽器,輸入http://localhost:5000。你可以看到歡迎界面。
如果需要使用IIS,在上一步驟中更改Debug Target 為 “IIS Express”即可。
這篇文章為本系列文章的最后一篇,感謝大家的關注。本系列的所有教程旨在幫助大家更好的理解ASP.NET 5,以便更好的進行開發。同時,也可以借助一些開發工具來助力開發過程。ComponentOne Studio for ASP.NET 是ASP.NET平台上的一整套完備的開發工具包,用於在各種瀏覽器中創建和設計具有現代風格的Web應用程序。
原文鏈接:http://www.asp.net/vnext/overview/aspnet-vnext/create-a-web-api-with-mvc-6