Universal App - 操作 Windows.Web.Http.HttpClient

Universal App - 操作 Windows.Web.Http.HttpClient

過去在撰寫 WP 的 App 時很常用到 WebClient 這個類別來操作網路資源或是交易,

我也寫過相關的介紹<Windows Phone 7 – 使用WebClient與HttpWebRequest的差異>。

但開始學習怎麼撰寫一個 Universal App 時,發現無法再使用 WebClient,而改用 HttpClient 這新的類別。

已寫過 Store App 對它應蠻熟悉,不過我是第一次使用,所以來了解怎麼操作它吧。

 

HttpClient

    利用 URI 負責傳送 HTTP request 與接收 HTTP response。它實作了:GET、POST、DELETE、PUT 方法,支援非同步的 Task。

這篇討論的是使用:Windows.Web.Http 下的 HttpClient,與過去 Win8 使用的 HttpClient (System.Net.Http.HttpClient) 不一樣。

 

重要屬性、方法與事件:

類型 名稱 說明
Methods DeleteAsync Send a DELETE request to the specified Uri as an asynchronous operation.
  Dispose [C#, VB] Performs tasks associated with freeing, releasing, or resetting unmanaged resources.
  GetAsync(Uri) Send a GET request to the specified Uri as an asynchronous operation.
  GetAsync(Uri, HttpCompletionOption) Send a GET request to the specified Uri with an HTTP completion option as an asynchronous operation.
  GetBufferAsync Send a GET request to the specified Uri and return the response body as a buffer in an asynchronous operation.
  GetInputStreamAsync Send a GET request to the specified Uri and return the response body as a stream in an asynchronous operation.
  GetStringAsync Send a GET request to the specified Uri and return the response body as a string in an asynchronous operation.
  PostAsync Send a POST request to the specified Uri as an asynchronous operation.
  PutAsync Send a PUT request to the specified Uri as an asynchronous operation.
  SendRequestAsync(HttpRequestMessage) Send an HTTP request as an asynchronous operation.
  SendRequestAsync(HttpRequestMessage, HttpCompletionOption) Send an HTTP request with an HTTP completion option as an asynchronous operation.
Properties DefaultRequestHeaders Read-only. Gets a collection of headers that should be sent with each request.

 

〉HttpClient class instance 扮演像似 session 負責傳遞 request 與接收 response。

〉HttpClient instance 是個設定集合,適用於所有由這個 instance 所發出的 reuqest。

每一個 HttpClient 使用各自的 connection pool,隔離開各自的 request,彼此 HttpClient 不會互相影響

〉HttpClient 可搭配 filters 為多種特定的 HTTP clients,例如:HttpClientFilter 可用於提供額外的方法給指定的 social network service;

〉使用 HttpClient 或相關在 Windows.Web.Http 下的類別下載大型檔案(超過 50MB),需改用 Stream 而不是使用預設的 Buffering

    =>因為 default buffering 使用的是 client memory,如果檔案太大會造成效能不佳的狀況;

〉HTTP Method 支援:DELETE, GET, PUT, and POST

〉Support for common authentication settings and patterns

〉Access to Secure Sockets Layer (SSL) details on the transport;

〉Ability to include customized filters in advanced apps;

〉Ability to get, set, and delete cookies

〉HTTP Request progress info available on asynchronous methods

 

簡單的範例如下:

using System;
using Windows.Foundation;
using Windows.Web.Http;
 
var uri = new Uri("http://example.com/datalist.aspx");
var httpClient = new HttpClient();
 
// Always catch network exceptions for async methods
try 
{
    var result = await httpClient.GetStringAsync(uri);
}
catch 
{
    // Details in ex.Message and ex.HResult.       
}
 
// Once your app is done using the HttpClient object call dispose to 
// free up system resources (the underlying socket and memory used for the object)
httpclient.Dispose();

<HttpClient class>提供的程式碼裡面有寫到「httpclient.Dispose()」,提示當 App 如對於 httpclient 已不需要時可呼叫 Dispose(),通知系統回收資源;

 

上述列表中列出呼叫 HttpClient 的重要方法,裡面有一些特殊的類別與列舉,以下分別加以介紹:

 

HttpRequestMessage

    呈現 HTTP Request 送出的內容;(HTTP messages are defined in RFC 2616 by the IETF)。

重要的屬性:

名稱 說明
Content Read/write,Gets or sets the HTTP content to send to the server on the HttpRequestMessage object.
Headers Read-only,Gets the collection of the HTTP request headers associated with the HttpRequestMessage.
取得 HttpRequestHeaderCollection 集合,藉由 Add、Remove、Keys 來操作指定的 Value;
Method Read/write,Gets or sets the HTTP method to be performed on the request URI.
Properties Read-only,Gets a set of properties on the HttpRequestMessage instance that are for use by the developer.
RequestUri Read/write,Gets or sets the Uri used for the HttpRequestMessage object.
TransportInformation Read-only,Get information about the underlying transport socket used by an HTTP connection.

HttpRequestMessage 包含:headers、HTTP verb 與 potentially data。通常它被用於需要為 HTTP Request 增加額外的參數或控制,例如:

‧執行 SSL/TLS transport information;

‧使用 less-common HTTP method;

‧額外對 HttpRequestMessage 設定的屬性;

 

 

HttpResponseMessage

    接收來自 HTTP Request 執行後所回傳的 HTTP Response message,裡面包括:headers、status code 與 data ;(HTTP messages are defined in RFC 2616 by the IETF)。

名稱 說明
Content Read/write,Gets or sets the content of the HTTP response message on the HttpResponseMessage object.
Headers Read-only,Gets the collection of HTTP response headers associated with the HttpResponseMessage that were sent by the server.
IsSuccessStatusCode Read-only,Gets a value that indicates whether the HTTP response was successful.
ReasonPhrase Read/write,Gets or sets the reason phrase which typically is sent by servers together with the status code.
RequestMessage Read/write,Gets or sets the request message which led to this response message.
Source Read/write,Gets the source of the data received in the HttpResponseMessage.
StatusCode Read/write,Gets or sets the status code of the HTTP response.
Version Read/write,Gets or sets the HTTP protocol version used on the HttpResponseMessage object.

HttpResponseMessage 通常來自 HttpClient 使用 DeleteAsync, GetAsync, PostAsync , PutAsync, or SendRequestAsync 這些方法。

 

了解 HttpRequestMessage 與 HttpResponseMessage後,以下範例說明如何使用:

private async void SendHttpRequestMessage()
{
    // 建立 HttpRequestMessage
    HttpRequestMessage requestMsg = new HttpRequestMessage(HttpMethod.Get, new Uri(""));
    // 修改 headers
    requestMsg.Headers.Add("myapp-deviceId", "univsersal app");
 
    HttpClient client = new HttpClient();
 
    // 利用 SendRequestAsync() 送出 HttpRequestMessage
    // await 後取得 HttpResponseMessage
    var response = await client.SendRequestAsync(requestMsg);
    String result = String.Empty;
    try
    {
        // 利用 EnsureSuccessStatusCode 確認是否成功
        // 如果失敗,EnsureSuccessStatusCode 會送出 Exception
        response.EnsureSuccessStatusCode();
 
        // 將 Http Content 轉換成 文字
        result = await response.Content.ReadAsStringAsync();
    }
    catch (Exception ex)
    {
        result = ex.Message;
    }
}

上述範例 HttpMethod 是 GET 如果您需要在 POST 也修改其 HttpRequestMessage,只需換成 HttpMethod.Post 即可 。

需注意,如果要送出 HttpRequestMessage 時,HttpClient 需要換成 SendRequestAsync();另外,上述有操作到 Http Content 的部分,往下便說有幾種 Content。

 

 

IHttpContent

    描述了 HTTP entity body、headers 與 cookies,這些內容做用於 HTTP Request 或 Response。利用 HttpClient 與網路服務交易時會得到 IHttpContent。

它是個 interface 定義了實作它的類別需要提供的方法:

類型 名稱 說明
Methods BufferAllAsync Serialize the HTTP content into memory as an asynchronous operation.
  ReadAsBufferAsync Serialize the HTTP content to a buffer as an asynchronous operation.
  ReadAsInputStreamAsync Serialize the HTTP content and return an input stream that represents the content as an asynchronous operation.
  ReadAsStringAsync Serialize the HTTP content to a String as an asynchronous operation.
  TryComputeLength Determines whether the HTTP content has a valid length in bytes.
  WriteToStreamAsync Write the HTTP content to an output stream as an asynchronous operation.
Properties Headers Read-only,Gets the collection of the HTTP request headers associated with the HttpRequestMessage.

 

Http Content 分有多種類型,其內容類型如下:

 

a. HttpBufferContent:利用 Buffer 呈現 HTTP content;

 

b. HttpStreamContent:利用 Stream 呈現 HTTP content,常使用於 HTTP GET 來接收資料與 HTTP POST 上傳資料。

 

c. HttpStringContent:利用 String 呈現內容,從 HTTP GET Request 取得的 HTTP Response 文字內容。

 

d. HttpFormUrlEncodedContent:使用 name/value tuples encoded 的方式呈現內容,並搭配特定的 application/x-www-form-urlencoded MIME type;

                                                         這也是一邊 POST Form 所使用的類型;

 

e. HttpMultipartContent:利用 multipart/* MIME type 代表 HTTP content;

 

f. HttpMultipartFormDataContent:利用 multipart/form-data MIME type 代表 HTTP content;與 HttpMultipartContent 相似,但它可以增加多個 IHttpContent,

                                                            屬於一個集合。

 

上述這幾種類型,常用的就是 HttpStringContent、HttpBufferContent 與 HttpStreamContent。

 

 

Windows.Web.Http.Headers

    支援 HTTP headers 與 cookies 的操作,header / cookies 的操作會影響 HttpRequestMessageHttpResponseMessage

常用的類別有:

HttpRequestHeaderCollection:a collection of the HTTP headers associated with an HTTP request.

                                                 例如:HttpRequestMessage.Headers 或 HttpClient.DefaultRequestHeaders;

HttpResponseHeaderCollection:a collection of the HTTP headers associated with an HTTP response.

                                                   例如:HttpResponseMessage.Headers;

HttpContentHeaderCollection:a collection of the HTTP headers associated with the content, which can be used on an HTTP request or response.

                                                 例如:實作 IHttpContent 的相關類別均是,如:HttpStringContent、HttpStreamContent…等;

 

 

Windows.Web.Http.Filters

   提供類別來發送 HTTP request 與 interface 建立篩選器針目標的 HTTP 和 REST service。常見是實作 IHttpFilter 介面。

Windows.Web.Http、Windows.Web.Http.Headers 與 Windows.Web.Http.Filters 為  Windows store apps 提供 HTTP Programming interface 來連接 HTTP services。

HttpBaseProtocolFilter:基本 HttpClient 使用的來傳送與接收資料的 Filter。詳細可參考:Windows.Web.Http.Filters

 

 

CancellationTokenIProgress<T> 介面

    CancellationToken:散佈通知,表示作業應被取消。詳細可參考<Managed 執行緒中的取消作業>,如果想要管理 Task 在特定情況下做取消的話,即

                                  需要實例化這個類別,並且將該 Token 指定給 Task,這樣在呼叫取消時才能統將該 Token 註冊的 Task 一併取消;

 

    IProgress<T> 介面:定義進度更新的提供者。T 代表要進度更新值的型別。以 HttpClient 來說即是 HttpProgress。建構子需要一個 Action<T> 的

                                    Handler 為參數,才能在進度狀態變化時通知處理預計要的任務。

 

 

HttpCookie class & HttpCookieCollection class & HttpCookieManager class

    操作 HTTP service 一定會遇到的 Cookie 處理,在 Windows.Web.Http 提供了幾個類別來處理:

HttpCookie:提供屬性集合與方法的集合負責管理一個 HTTP cookie。為一個小單位;

名稱 說明
Domain Read-only,Get the domain for which the HttpCookie is valid.
Expires Read/write,Get or set the expiration date and time for the HttpCookie.
HttpOnly Read/write,Get or set a value that controls whether a script or other active content can access this HttpCookie.
Name Read-only,Get the token that represents the HttpCookie name.
Path Read-only,Get the URI path component to which the HttpCookie applies.
=>Path:代表對於應 URI 中那一個路徑可使用這個 Cookie;
=>Path 屬性指定 Uri 的子集此 Cookie 適用的源伺服器上
    如果未指定此屬性,則此 Cookie 將送交起源或多個伺服器上的所有頁面。
=>舉例來說:http://www.dotblogs.com.tw/,在設定它的 Path 可以是 /dotblogs/;
Secure Read/write,Get or set the security level for the HttpCookie.
Value Read/write,Get or set the value for the HttpCookie.

 

HttpCookieCollection:集合多個 HttpCookie,由 HttpCookieManager.GetCookies 取得;

 

HttpCookieManager: 負責管理所有的 HttpCookies;

 

藉由下方的程式範例來說明:

a) 設定 Cookie:

private void SetCookie()
{
    HttpCookie cookie = new HttpCookie("userId", "dotblogs.com.tw", "http://www.dotblogs.com.tw");
    cookie.Value = "Pou";
    cookie.Expires = DateTime.UtcNow.Date.AddMinutes(3);
    cookie.HttpOnly = true;
    cookie.Secure = true;
 
    // 取得 HttpClient 預設使用的 HttpBaseProtocolFilter 元素
    HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
    // 放入 Cookie
    bool replaced = filter.CookieManager.SetCookie(cookie, false);
 
    HttpClient client = new HttpClient(filter);
}

 

b) 取得 Cookie:

private void GetCookie()
{          
    HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
    HttpCookieCollection cookieCollection = filter.CookieManager.GetCookies(
                                new Uri("http://www.dotblogs.com.tw"));
    foreach (var item in cookieCollection)
    {
        String value = String.Format("key: {0}, value: {1}", item.Name, item.Value);
    }
}

 

 

HttpProgress structure

    呈現 HttpClient 執行過程中的狀態資訊。具有以下值:

Field Data type Description
BytesReceived System.UInt64

The total number of bytes received.

This value includes bytes received as response headers.

If the operation was restarted, this value may be smaller than in the previous progress report.

BytesSent System.UInt64

The total number of bytes sent.

This value includes bytes sent as request headers.

If the operation was restarted, this value may be smaller than in the previous progress report.

Retries System.UInt32 The number of retries.
Stage HttpProgressStage The step in the progress of an HTTP connection.
TotalBytesToReceive System.Nullable<UInt64>

The total number of data bytes to receive.

If the number is unknown, this value is 0.

TotalBytesToSend System.Nullable<UInt64>

The total number of data bytes to send.

If the number is unknown, this value is 0.

 

HttpTransportInformation class

    提供有關 HTTP 連接所使用的底層傳輸資訊。該類別主用於 SSL Connection 取得 SSL 資訊。

重要屬性如下:

名稱 說明
ServerCertificate Read-only,Gets the certificate from the server with the SSL information.
ServerCertificateErrors Read-only,Gets the list of errors that occurred making an SSL connection.
ServerCertificateErrorSeverity Read-only,Gets the category of an error on an SSL connection.
ServerIntermediateCertificates Read-only,Gets the intermediate certificates sent by the server during SSL negotiation on this HttpTransportInformation object.

 

 

在操作 HttpClient 時相關的列舉值:

HttpCompletionOption

    用於提示 HttpClient 在非同步執行時是已完成所有 response 的讀取或是當 header 已被讀取的訊息列舉。

Member Description
ResponseContentRead 0,The operation should complete after reading the entire response including the content. This is the default value.
ResponseHeadersRead 1,The operation should complete as soon as a response is available and headers are read. The content is not read yet.

 

 

HttpVersion enumeration

    呈現 HTTP Protocol Version。

Member Description
None 0,This value may be returned by third party filters.
Http10 1,HTTP 1.0.
Http11 2,HTTP 1.1.

 

 

 

[範例]

a. 實作 GET 方法來取得遠端音樂檔案

public async void LoadRemoteMusicFile(String id, String pwd)
{
    HttpRequestMessage requestMsg = new HttpRequestMessage(
                                        HttpMethod.Get, 
                                        new Uri(""));
    requestMsg.Headers.Add("uid", WebUtility.UrlEncode(id));
    requestMsg.Headers.Add("pwd", WebUtility.UrlEncode(pwd));
    // 利用 HttpRequestMessage 與 HttpResponseMessage 來操作
    HttpClient client = new HttpClient();
    var responseMsg = await client.SendRequestAsync(requestMsg);
    try
    {
        responseMsg.EnsureSuccessStatusCode();
        // 在 Local Folder 建立要儲存的檔案
        StorageFile musicFile = await GetMusicFile("temp.mp3");
        // 將 StorageFile 開啟可寫入的 Stream
        IRandomAccessStream writeStream = await musicFile.OpenAsync(FileAccessMode.ReadWrite);
        // 將 Http response 收到的 http content 寫入 Stream
        ulong writeLengths = await responseMsg.Content.WriteToStreamAsync(writeStream);
 
        ulong length = 0;
        responseMsg.Content.TryComputeLength(out length);
 
        // 判斷是否完整寫入
        if (writeLengths == length)
        {
            MediaElement media = new MediaElement();
            media.Source = new Uri("ms-appdata:///local/temp.mp3");
            media.AutoPlay = true;                    
            content.Children.Add(media);
        }
    }
    catch (Exception ex)
    {
        // handle exception
    }
 
}
 
private async Task<StorageFile> GetMusicFile(String name)
{
    StorageFolder local = ApplicationData.Current.LocalFolder;
    StorageFile file = null;
    try
    {
        file = await local.GetFileAsync(name);
    }
    catch (FileNotFoundException) { }
    if (file == null)
    {
        file = await local.CreateFileAsync(name, CreationCollisionOption.ReplaceExisting);
    }
    return file;
}

需注意要寫入時,使用 Stream 的方式所以要將 StorageFile 先開啟寫入的 IRandomAccessStream,再將 HTTP content 的內容寫入。

 

b. 實作 POST 方法來交易資料

b-1. POST HttpStringContent:

private async void SendStringPostData()
{
    // 傳送 文字 內容
    HttpStringContent strContent = new HttpStringContent("hello world");
 
    HttpClient client = new HttpClient();
    var response = await client.PostAsync(new Uri("http://localhost:4347/WebForm1.aspx"), strContent);
    try
    {
        response.EnsureSuccessStatusCode();
        // 取得回傳結果
        String result = await response.Content.ReadAsStringAsync();
    }
    catch (Exception)
    {
        // handle exception
    }
}

 

b-2. POST HttpMultipartFormDataContent:

private async void SendMultiFormContent()
{
    try
    {
        // 利用 HttpMultipartFormDataContent 逐一加入要傳送的參數
        HttpMultipartFormDataContent form = new HttpMultipartFormDataContent();
        form.Add(new HttpStringContent("Pou"), "key");
        form.Add(new HttpStringContent("Windows Phone"), "value");
 
        HttpClient client = new HttpClient();
        HttpResponseMessage response = await client.PostAsync(new Uri("http://localhost:4347/WebForm1.aspx"), form);
 
        response.EnsureSuccessStatusCode();
 
        String result = await response.Content.ReadAsStringAsync();
    }
    catch (TaskCanceledException)
    {
    }
    catch (Exception ex)
    {
    }
    finally
    {
    }
}

 

b-3. POST HttpStreamContent:

private async void PostStreamData()
{
    try
    {
        Uri uri = new Uri("http://localhost:4347/WebForm1.aspx");
 
        // 在 Local Folder 建立要儲存的檔案
        StorageFile musicFile = await GetMusicFile("temp.mp3");
        Stream stream = await musicFile.OpenStreamForReadAsync();
 
        // 利用 HttpStreamContent 包裝要送出的 Stream
        HttpStreamContent streamContent = new HttpStreamContent(stream.AsInputStream());
 
        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
        request.Content = streamContent;
 
        // Do an asynchronous POST.
        HttpClient client = new HttpClient();
        HttpResponseMessage response = await client.SendRequestAsync(request);
    }
    catch (Exception)
    {
 
    }
}

如果您要 POST 的 HTTP Content 是自訂的話,可實作 IHttpContent 介面來加以支援;

 

c. 修改 Http Header

private void ChangeHttpHeader()
{
    HttpClient httpClient = new HttpClient();
 
    // Add a user-agent header
    var headers = httpClient.DefaultRequestHeaders;
 
    // 加入需要的 Header
    headers.UserAgent.ParseAdd("ie");
    headers.UserAgent.ParseAdd("Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
}

 

e. 實作 Progress 的呈現

public async void LoadRemoteMusicFile(String id, String pwd)
{
    HttpRequestMessage requestMsg = new HttpRequestMessage(
                                        HttpMethod.Get, 
                                        new Uri("https://dl.dropboxusercontent.com/u/18944013/illa%20illa%20.mp3"));
    requestMsg.Headers.Add("uid", WebUtility.UrlEncode(id));
    requestMsg.Headers.Add("pwd", WebUtility.UrlEncode(pwd));
 
    // 加入 Progress Handler
    Progress<HttpProgress> progressCallback = new Progress<HttpProgress>(OnSendRequestProgress);
    var tokenSource = new CancellationTokenSource();
 
    // 利用 HttpRequestMessage 與 HttpResponseMessage 來操作
    HttpClient client = new HttpClient();
    var responseMsg = await client.SendRequestAsync(requestMsg).AsTask(tokenSource.Token, progressCallback);
 
    try
    {
        responseMsg.EnsureSuccessStatusCode();
        // 在 Local Folder 建立要儲存的檔案
        StorageFile musicFile = await GetMusicFile("temp.mp3");
        // 將 StorageFile 開啟可寫入的 Stream
        IRandomAccessStream writeStream = await musicFile.OpenAsync(FileAccessMode.ReadWrite);
        // 將 Http response 收到的 http content 寫入 Stream
        ulong writeLengths = await responseMsg.Content.WriteToStreamAsync(writeStream);
 
        ulong length = 0;
        responseMsg.Content.TryComputeLength(out length);
 
        // 判斷是否完整寫入
        if (writeLengths == length)
        {
            MediaElement media = new MediaElement();
            media.Source = new Uri("ms-appdata:///local/temp.mp3");
            media.AutoPlay = true;                    
            content.Children.Add(media);
        }
    }
    catch (Exception ex)
    {
        // handle exception
    }
}
 
private void OnSendRequestProgress(HttpProgress obj)
{
    // 更新畫面中的 ProgressBar
    this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High,
        () => {
            btnBar.Minimum = 0;
            btnBar.Value = obj.BytesReceived;
            if (obj.TotalBytesToReceive != null)
                btnBar.Maximum = (double)obj.TotalBytesToReceive;
        });
}

主要實作一個 Progress<HttpProgress> 處理函式,來接收把 SendRequestAsync 轉換成一個 Task,並將 ProgressHandler 指定給它。

 

更多的範例參考<HttpClient sample>的內容

[範例檔案]

 

[補充]

1) System.Net.Http.HttpClientWindows.Web.Http.HttpClient 的差別

    Win8 操作 HttpClient 使用 System.Net.Http.HttpClient,Win8.1 後改用 Windows.Web.Http.HttpClient;

    Windows.Web.Http.HttpClient 取代了三種舊的 namespace:

    a. WinJS.xhr for JavaScript;

    b. System.Net.Http.HttpClient in the System.Net.Http namespace for C# and VB.

        (Not supported on Windows Phone. WP8.1 之前不支援 HttpClient)

    c. XML HTTP Extended Request (IXMLHTTPRequest2) for C++;

    詳細請參考<How to connect to an HTTP server using Windows.Web.Http.HttpClient (XAML)>。

 

2) 處理相關 Exception 可參考<Handling exceptions in network apps>;

 

======

這篇寫到後來有點把 HttpClient 我覺得會操作到的內容都寫上了,主要是因為之前在寫 WP8 的時候,

我很習慣使用 HttpWebRequest 來操作網路服務,所以就把在裡面遇到過的問題與疑惑都在撰寫 HttpClient 時都補上,

希望有幫助到大家,謝謝。如果有問題,也歡迎指教與討論。謝謝。

 

Referecnes

Connecting to networks and web services (XAML) (重要)

How to connect to an HTTP server using Windows.Web.Http.HttpClient (XAML) (重要)

Connecting to an HTTP server using System.Net.Http.HttpClient (Windows Store apps using C#/VB and XAML)

How to enable loopback and debug network isolation

How to configure network isolation capabilities

Handling exceptions in network apps (重要)

How to set timeouts on socket operations (重要)

Connecting to web services & Web authentication sample

HttpClient Sample (重要)

Downloading files in Windows 8 apps using Background Transfer feature

Connecting using XML HTTP Request and IXMLHTTPRequest2 (Windows Runtime apps using C++ and XAML)

How to connect to Bing Maps using Windows::Web::Http::HttpClient (Windows Runtime apps using C++ and XAML)

C# HttpClient & [Web API] WinForm 使用 HttpClient 呼叫 Web API