驀然回首,那些年,我竟然一直很二。
小時候,讀武俠小說的時候,看到那些豬腳,常常會產生一種代入感,幻想自己也會遭遇某種奇遇,遇到懸崖跳下去是不是有本“武林秘笈”在等着?長大以后也是一樣,多少人夢着醒着都在想,沒准哪一天自己也會成為“億萬富翁”。打住!你不是“萬中無一”,也沒那么多沒准!當然,有時候還需要一點運氣。
生活了二十幾年,想做的事不少,狠下心做成的當真沒幾件,想想並不是資質愚鈍,而是缺乏想到做到的勁頭。為什么會這樣?也許這就是惰性!就像大學時候打算考一大堆什么證,可是剛開始總感覺時間如此充裕以至於完全可以先打打游戲,看看大片,聽聽音樂,等終於打開書本時才發現:沒時間了!就像畢業后打算定期一篇博客園隨筆,可是不知不覺“太監”了15個月了。
前些天我給自己買了一包煙,然后蹲坐在樓梯口,用食指有節奏的輕點腮幫子,抹了把唏噓的胡渣,望着彌漫在眼前層層疊疊的煙圈,那么憂郁、迷茫、空洞,嘆一句:“原來我已經畢業*個月了!時間真快!”其實,我知道是我太急於求成了。今天,我充滿干勁的喊上一句:“我才畢業*個月!我還年輕,我有資本!”你說,我是不是很二?
閑話少扯……
1. 概述
顧名思義,ASP.NET Web API 是一個用於在 .NET Framework 上生成 Web API 的框架,Web API 可以理解為是一個基於 RESTful 的 Web 服務(IIS 承載的 WCF 服務是一個基於 SOAP 的 Web 服務),即滿足 REST 原則的 Web 服務。
那么,什么是 REST 原則?要理解 REST 原則,我們先來理解一下 REST (Representational State Transfer) 這個詞語到底是什么意思,每一個單詞代表了什么涵義。
Representational 其實指的是“資源”,資源是一個有趣的概念實體,它可以是一個應用程序對象,可以是一條數據庫記錄,也可以是一個算法等等。在基於 RESTful 的 Web 服務中,每個資源都使用 URI 統一資源標識符(Universal Resource Identifier) 得到一個惟一的地址。資源本身都是方法調用的目標,它向客戶端公開,通過 HTTP 協議標准方法 GET、PUT、POST 和 DELETE 處理和傳輸狀態,即 State Transfer 狀態轉移。
而我們都知道 HTTP 協議是一個無狀態協議,也就是說 HTTP 協議對於事務處理沒有記憶能力,如果后續需要處理前面的信息,則它必須重傳。這就意味着客戶端和服務器之間的交互在請求之間是無狀態的。從客戶端到服務器的每個請求都必須包含理解請求所必需的信息。如果服務器在請求之間的任何時間點重啟,客戶端不會得到通知。此外,無狀態請求可以由任何可用服務器回答,另一方面服務器不需要先前信息時它的應答就較快,這十分適合雲計算之類的環境,客戶端可以緩存數據以改進性能,畢竟可能導致每次連接傳送的數據量增大。
2. 創建一個 Web API 項目
在 Visual Studio 2012 中新建項目或添加新項目,然后在模板窗格中,選擇已安裝的模板和展開 Visual C# 節點。在 Visual C# 中,選擇 Web。在項目模板的列表中,選擇 ASP.NET MVC 4 Web 應用程序。在新的 ASP.NET MVC 4 項目對話框中,選擇 Web API 並單擊確定。

3. 添加模型和 Web API 控制器
ASP.NET Web API 可以自動序列化模型到 JSON、 XML 或一些其他格式,然后將序列化的數據寫入到 HTTP 響應消息的正文。下面我們創建一個簡單的“產品”模型:
1 /// <summary> 2 /// Product 實體 3 /// </summary> 4 public class Product 5 { 6 /// <summary> 7 /// ID 8 /// </summary> 9 public int Id { get; set; } 10 11 /// <summary> 12 /// 名稱 13 /// </summary> 14 public string Name { get; set; } 15 16 /// <summary> 17 /// 類別 18 /// </summary> 19 public string Category { get; set; } 20 21 /// <summary> 22 /// 價格 23 /// </summary> 24 public decimal Price { get; set; } 25 }
在 ASP.NET Web API 中,控制器是一個類,處理 HTTP 請求。Web API 控制器繼承 ApiController 類而不是 Controller 類,它的操作返回的是數據而不是視圖。在示例 Product WebAPI 控制器 ProductsController.cs 中定義了5個操作,每個操作映射到一個 URI,客戶端可以通過發送 HTTP GET 請求的 URI 來調用該操作。
1 /// <summary> 2 /// Product Web API 控制器 3 /// </summary> 4 public class ProductsController : ApiController 5 { 6 /// <summary> 7 /// Product 數據源 8 /// </summary> 9 Product[] products = new Product[] 10 { 11 new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, 12 new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, 13 new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } 14 }; 15 16 // GET api/products 17 public IEnumerable<Product> Get() 18 { 19 return products; 20 } 21 22 // GET api/products/5 23 public Product Get(int id) 24 { 25 var product = products.FirstOrDefault(p => p.Id == id); 26 if (product == null) 27 { 28 throw new HttpResponseException(HttpStatusCode.NotFound); 29 } 30 return product; 31 } 32 33 // POST api/products 34 public void Post([FromBody]string value) 35 { 36 } 37 38 // PUT api/products/5 39 public void Put(int id, [FromBody]string value) 40 { 41 } 42 43 // DELETE api/products/5 44 public void Delete(int id) 45 { 46 } 47 }
4. 注冊 Web API 全局配置(路由默認值)
MVC Web 應用程序使用 Global.asax 文件中的代碼來設置全局 URL 路由默認值,並且使用 Web.config 文件來配置應用程序。路由在 Global.asax 文件的 Application_Start 方法中初始化。那么,Web API GlobalConfiguration 呢?
1 /// <summary> 2 /// 應用程序啟動 3 /// </summary> 4 protected void Application_Start() 5 { 6 Register(GlobalConfiguration.Configuration); // 注冊全局配置 7 } 8 9 /// <summary> 10 /// 注冊全局配置 11 /// </summary> 12 /// <param name="config">使用 HTTP 路由集合初始化的 HTTP 配置</param> 13 public static void Register(HttpConfiguration config) 14 { 15 config.Routes.MapHttpRoute( 16 name: "DefaultApi", 17 routeTemplate: "api/{controller}/{id}", 18 defaults: new { id = RouteParameter.Optional } 19 ); 20 21 config.EnableSystemDiagnosticsTracing(); 22 }
到此為止,Web API GlobalConfiguration 已注冊完畢。ASP.NET Web API 包含 ApiExplorer 類對每個 Web API 操作進行說明。 那么,如何通過 GlobalConfiguration 獲取 ApiExplorer 呢?於是,啟動調試添加監視:

當然,可以隱藏 ApiExplorer 類中的 ApiDescription,將 ApiExplorerSettings 屬性添加到 Web API 操作,將 IgnoreApi 設置為 true。此外可以將此屬性添加要排除的整個 Web API 控制器。
1 /// <summary> 2 /// Product Web API 控制器 3 /// </summary> 4 public class ProductsController : ApiController 5 { 6 /// <summary> 7 /// Product 數據源 8 /// </summary> 9 Product[] products = new Product[] 10 { 11 new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, 12 new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, 13 new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } 14 }; 15 16 // GET api/products 17 public IEnumerable<Product> Get() 18 { 19 return products; 20 } 21 22 // GET api/products/5 23 public Product Get(int id) 24 { 25 var product = products.FirstOrDefault(p => p.Id == id); 26 if (product == null) 27 { 28 throw new HttpResponseException(HttpStatusCode.NotFound); 29 } 30 return product; 31 } 32 33 // POST api/products 34 [ApiExplorerSettings(IgnoreApi = true)] 35 public void Post([FromBody]string value) 36 { 37 } 38 39 // PUT api/products/5 40 [ApiExplorerSettings(IgnoreApi = true)] 41 public void Put(int id, [FromBody]string value) 42 { 43 } 44 45 // DELETE api/products/5 46 [ApiExplorerSettings(IgnoreApi = true)] 47 public void Delete(int id) 48 { 49 } 50 }
啟動調試添加監視:

1 public HelpController() 2 : this(GlobalConfiguration.Configuration) 3 { 4 } 5 6 public HelpController(HttpConfiguration config) 7 { 8 Configuration = config; 9 } 10 11 public HttpConfiguration Configuration { get; private set; }
5. 使用瀏覽器調用 Web API
在 Visual Studio 中,選擇啟動調試或使用鍵盤快捷鍵 F5。本地 IIS Web 服務器 IIS Express 將啟動,並隨機選擇生成的端口號。當然也可以在項目屬性中,選擇 Web 中配置服務器和 URL。

使用 F12 開發人員工具,單擊網絡選項卡,然后按開始捕獲“api/products/”和“api/products/id”的 HTTP 請求和響應。




6. 使用 Javascript 和 jQuery 調用 Web API
其實,大部分 Web API 都要由客戶端應用程序以編程方式調用的。如下使用 JQuery getJSON 函數向“api/products”發送一個 AJAX 請求,響應包含的 JSON 對象的數組。
1 @section scripts { 2 <script> 3 var apiUrl = 'api/products'; 4 5 $(document).ready(function () { 6 //發送 AJAX 請求 7 $.getJSON(apiUrl) 8 //done 函數指定如果請求成功,則調用的回調 9 .done(function (data) { 10 $.each(data, function (key, item) { 11 $('<li>', { text: item.Name + ': $' + item.Price }).appendTo($('#div')); 12 }); 13 }); 14 }); 15 </script> 16 }
