System.Net.Http 簡介
System.Net.Http 是微軟推出的最新的 HTTP 應用程式的編程介面, 微軟稱之為“現代化的 HTTP 編程介面”, 旨在提供如下內容:
- 使用者通過 HTTP 使用現代化的 Web Service 的用戶端組件;
- 能夠同時在用戶端與服務端同時使用的 HTTP 組件(比如處理 HTTP 標題和訊息), 為用戶端和服務端提供一致的編程模型。
命名空間 System.Net.Http 以及 System.Net.Http.Headers 提供了如下內容:
- HttpClient 發送和接收 HTTP 要求與響應;
- HttpRequestMessage and HttpResponseMessage 封裝了 RFC 2616 定義的 HTTP 訊息;
- HttpHeaders 封裝了 RFC 2616 定義的 HTTP 標題;
- HttpClientHandler 負責產生HTTP響應訊息的HTTP處理常式。
System.Net.Http 能夠處理多種類型的 RFC 2616 定義的 HTTP 實體本文, 如所示:
此外, System.Net.Http 對 HTTP 訊息的處理採用了職責鏈模式, 這裡有一遍不錯的介紹, 這裡就不再多說了。
Silverlight 版本的 System.Net.Http
System.Net.Http 最早和 Asp.Net Mvc4 同時出現, 可以在 .Net 4.0 中使用。 隨著 .Net 4.5 的發布, System.Net.Http 正式成為 .Net 基礎類庫, 目前已經可以在 .Net 4.0/4.5 、 Windows Phone 、 以及 Windows Store App 中使用, 唯獨沒有發布 Silverlight 版本的 System.Net.Http。 更加悲催的是, 隨著 Xamarin 2.0 的發布, Xamarin.Android 和 Xamarin.iOS 居然也開始支援 System.Net.Http , 真是讓做 Silverlight 開發的碼農心寒。
幸好, .Net 有開源的實現, 那就是 Mono , 其中有大量開源的 .Net 基礎類實現, 在 Mono 3.x 版本中, 就有開源的 System.Net.Http , Xamarin 發布的 Android 和 iOS 版本的 System.Net.Http 就是源自 Mono 的, 既然 Android 和 iOS 可以, 相信 Silverlight 也肯定可以, 抱著試試看的態度, 下載了 Mono 下的 System.Net.Http 原始碼, 並整理成了一個 Silverlight 項目。 經過一番努力, Silverlight 版本的 System.Net.Http 終於可以使用了, GitHub 項目地址: https://github.com/beginor/System_Net_Http , 歡迎圍觀。
由於 Silverlight 平台對 HTTP 的限制, 移除了部分功能, 例如 Proxy 、 AllowAutoRedirect 、 PreAuthenticate 以及 KeepAlive 設定等, 這些都是 Silverlight 不支援的。
對於 Silverlight 的 BrowserHttp , 僅僅支援 GET 和 POST 方法, 範例程式碼如下:
HttpClient client = new HttpClient { BaseAddress = new Uri("http://localhost:8080/HttpTestWeb/api/")};// Get string from serverclient.GetStringAsync("browserhttp/").ContinueWith(t => { if (t.IsFaulted) { // report error here //Application.Current.ReportError(t.Exception.GetBaseException()); } else { string txt = t.Result; //Assert.IsFalse(string.IsNullOrEmpty(txt)); }});// Post form data to servervar param = new Dictionary<string, string> { {"Name", "Client Post"}, {"Age", "1"}, {"Birthday", DateTime.Today.ToString("s")}};client.PostAsync("browserhttp/", new FormUrlEncodedContent(param)).ContinueWith(t => { if (t.IsFaulted) { // report error here // Application.Current.ReportError(t.Exception.GetBaseException()); } else { HttpResponseMessage response = t.Result; //Assert.IsTrue(response.EnsureSuccessStatusCode); }});
對於 ClientHttp , 除了 GET 和 POST 之外, 還支援 PUT 和 DELETE (其它的 HTTP 方法也可能支援, 未測試), 範例程式碼如下:
// PUT to updatevar param = new Dictionary<string, string> { {"Id", "1" }, {"Name", "Client Post"}, {"Age", "1"}, {"Birthday", DateTime.Today.ToString("s")}};client.PutAsync("clienthttp/1", new FormUrlEncodedContent(param)).ContinueWith(t => { if (t.IsFaulted) { // report error here // Application.Current.ReportError(t.Exception.GetBaseException()); } else { HttpResponseMessage response = t.Result; //Assert.IsTrue(response.EnsureSuccessStatusCode); }});// DELETEclient.DeleteAsync("clienthttp/1").ContinueWith(t => { if (t.IsFaulted) { // report error here // Application.Current.ReportError(t.Exception.GetBaseException()); } else { HttpResponseMessage response = t.Result; //Assert.IsTrue(response.EnsureSuccessStatusCode); }});
支援職責鏈模式的 MessageProcessingHandler , 如下面的代碼所示:
public class CustomProcessingHandler : MessageProcessingHandler { protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken) { if (request.Method != HttpMethod.Get && request.Method != HttpMethod.Post) { request.Headers.TryAddWithoutValidation("RequestMethod", request.Method.Method); request.Method = HttpMethod.Post; } return request; } protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken) { var request = response.RequestMessage; if (request.Headers.Contains("RequestMethod")) { IEnumerable<string> values; if (request.Headers.TryGetValues("RequestMethod", out values)) { request.Method = new HttpMethod(values.First()); } } return response; }}
使用起來也是非常簡單的:
var customHandler = new CustomProcessingHandler { InnerHandler = new HttpClientHandler()};var client = new HttpClient(customHandler, true) { BaseAddress = new Uri("http://localhost:8080/HttpTestWeb/api/")};
參考資料:
- MSDN 官方文檔:http://msdn.microsoft.com/library/system.net.http.aspx
- ASP.NET Web API 介紹中的 Working with HTTP: http://www.asp.net/web-api/overview/working-with-http
- Mono 原始碼: https://github.com/mono/mono/tree/master/mcs/class/System.Net.Http