在<Windows Phone 7-下載檔案至Isolated Storage>提到了透過WebClient的功能將網站上的檔案下載至

WP7的Isoated Storage之中。但實際的WebClient卻沒有仔細的提到,因此該篇將針對WebClient做說明,

另外想接著介紹相關於HttpWebRequest的使用,以及這二個類別之間的差異與對於WP7的一個影響。

 

在討論WebClient與HttpWebRequest之前,要先了解一下一個蠻重要的類別:WebRequest類別。

‧WebRequest

它是.NET Framework進行處理網際網路資源要求(WebRequest)與回應(WebResponse)的主要模型。屬於Abstract類別。

沒有辦法直接透過建構子實作,需使用:​​WebRequest.Create​​方法來建立實體來進行運用。該類別還有其他相關不同

於通訊協定的類別,包括:WebRequestMethod.File、WebRequestMethod.Ftp與WebRequestMethod.Http。更詳細的使

用方法,可以參考<如何使用 WebRequest 類別要求資料>這篇有詳細的說明。

 

然而,在Silverlight所支援的Syste.Netm命名空間裡,目前僅支援:WebRequest、WebResponse、WebClient與

HttpWebRequest等類別,雖然缺少了WebRequestMethod.Ftp或FtpWebRequest就代表Silverlight沒法支援FTP了嗎?

答案是否定的。因為WebClient還是可以做到相同的效果(但需注意Timeout問題),因為WebClient是一個非常特別

好用的封裝後類別,讓我們開發人員非常容易就可以撰寫出擷取網路資源的程式。另外,也可以參考以下的文章:

​Silverlight 3 File Transfer Application​​。

 

那麼接下來就回到主題裡,談論相關於Silverlight下的WebClient與HttpWebRequest二個常用於Silverlight的類別。

‧WebClient

WebClient使用WebRequest類別提供對資源的存取。WebClient類別相較於HttpWebRequest類別,它比較像是個被

封裝完成專門處理網路資源存取的類別,例如:依照預設值,當使用WebClient時,該執行個體是不會傳送選擇性

的Http標頭,也就是它會依舊你使用的URI產生相對應的Http Header內容,讓接收端可以有效擷取需要的內容。

這樣的好處可以讓開發人員依基本的Header來完成任務。但其實對於Header的使用,還是有其限制在的,可以參考

<​​WebHeaderCollection 類別​​>這篇文章的介紹,裡面提供了那些Header可以操作來向接收端進行溝通。


Method



Description



OpenWriteAysnc



以非同步方式擷取用於將資料傳送至資源的 ​​Stream​​,而不封鎖呼叫的執行緒。使用 POST 命令上載 HTTP 資源。該方法將資料轉入資料流中進行傳送。



UploadStringAsync



將 ​​String​​ 傳送至資源,而不封鎖呼叫的執行緒。指定上傳的URI 必須識別出可以接受使用 POST 方法傳送之要求的資源。



DownloadStringAsync



從資源下載 ​​String​​,而不封鎖呼叫的執行緒。採用GET方法向URI下載指定資源。



OpenReadAsync



以非同步方式從資源傳回資料,而不封鎖呼叫的執行緒。採用下載封裝的方式,讓資源回傳時是屬於一個獨立的檔案集合。採用GET方法向URI下載指定資源。


上方四種是常用於非同步作業使用的方法。然而在使用WebClient類別需要注意Silverlight針對網路存取的限制,可以參考

:<Silverlight 中的網路安全性存取限制>與<Silverlight 中的 URL 存取限制>。另外,也許你會像我一樣不太了解為何有一

個DownloadStringAsync或UploadStringAsync的方法出現,因為在網路上搜尋看到WebClient類別的範例都是使用另外二種:

OpenWriteAsync與OpenReadAsync來儲存網路資源。也許你可以依照下方的分類來按需求使用:

〉DownloadStringAsync/UploadStringAsync:適用於當接收端接受傳送資料的類型,例如:XML、JSON等其他相關文字類型。

〉OpenWriteAsync/OpenReadAsync:適用接收端使用POST方式接收/取得資料流的類型,例如:可轉成Stream的資料料型。

 

‧HttpWebRequest

它是WebRequest的子代類別,實作WebRequest提供的方法與屬性,主要針對Http Protocol進行處理,內部包括了Header、

Content等一般在ASP.NET網頁中Request看到的屬性。讓用戶可以直接與Http伺服器進行溝通,例如:Get或Post。

它使用的方法,如同WebRequest類別的用法:WebRequest.Create根據URI中的http或https回傳HttpWebRequest 物件。

然而使用HttpWebRequest特別注意:「Silverlight執行階段會限制HttpWebReuqest類別從特定的Header傳送到跨網域網站」

該限制主要是避免程式進行跨網域存取的問題,造成類別跨網域攻擊的事件發生,也能確保資源是安全與規範下的存取。

另外,更詳細說明安全性的問題可以參考:<Silverlight 中的網路安全性存取限制>與<Silverlight 中的 URL 存取限制>。

 

主要使用的Method:


Method Name



Description



BeginGetResponse



開始對網際網路資源的非同步要求。



EndGetResponse



結束對網際網路資源的非同步要求。需使用IAsyncResult處理回傳結果。



BeginGetRequestStream



開始用來寫入資料之 Stream 物件的非同步要求。



EndGetRequestStream



結束用來寫入資料之 Stream 物件的非同步要求。需使用IAsyncResult處理回傳結果。


以上二組方法均是Request/Response的相對應(另外還有GetResponse()等支援同步作業的方法)。由於二者均屬於非同步的呼叫,

因此另外有二個重要的類別需要注意:

〉​​AsyncCallback委派

提供讓用戶端應用程式完成非同步的作業。在啟始非同步作業時,提供戶用端這個回呼委派。AysncCallback所參考的事件

處理常式包含完成處理非同步作業的工作邏輯。然而回傳的結果則語IAsyncResult介面來控制。

 

〉​​IAsyncResult介面​

由執行非同步作業方法的類別所實作。代表非同步作業開始與結束的回傳型別(Return Type)。它會配搭非同步作業完成時,

交由AsyncCallback委派所叫用(invoke)的方法回傳資訊。

 

以下舉了一個簡單的使用範例:

我實作了一個Default.aspx的網頁,接受透過GET的方法把User的帳號與密碼送到該網頁來取得驗證的動作。(範例有點不好,

但重點在說明如何使用HttpWebRequest類別)。




1: private void button1_Click(object sender, RoutedEventArgs e)
2: {
3:     //建立HttpWebReuqest實體
4:     HttpWebRequest tHReuqest = WebRequest.CreateHttp("http://localhost:1294/Default.aspx?UID=pou&PWD=pou1234");
5:     //使用AsyncCallback委派,來完成非同步的作業。
6:     tHReuqest.BeginGetResponse(new AsyncCallback(ResponseCallback), tHReuqest);
7: }
8:
9: private void ResponseCallback(IAsyncResult asynchronousResult)
10: {
11:     //使用AsyncCallback委派需要實作IAsyncResult介面來取得非同步作業的狀態。
12:     HttpWebRequest tRequest = (HttpWebRequest)asynchronousResult.AsyncState;
13:     HttpWebResponse tResponse = (HttpWebResponse)tRequest.EndGetResponse(asynchronousResult);
14:     using (StreamReader tResponseStream = new StreamReader(tResponse.GetResponseStream()))
15:     {
16:         string strResult = tResponseStream.ReadToEnd();
17:         //將Response內容讀入後,透過呼叫UI Thread來修改畫面中元件的顯示。
18:         Dispatcher.BeginInvoke(() =>
19:         {
20:             textBox1.Text = strResult;
21:         });
22:     }
23: }


 

‧WebClient & HttpWebRequest 不同之處

WebClient與HttpWebReuqest對於我剛學習Silverlight時,我一直搞不清楚何該用那一種類型會比較適用,

也許你參考過這一篇<Using WebClient and HttpWebRequest>,它裡面也提及由於二個類別使用,如果是用於

比較單純的情境(例如:單純透過GET去取得指定URI所回傳的內容或檔案),二者的差異是比較小的,也就比

較容易造成混淆。但是如果按照上述所描述二者各自的用途與功能後,可以容易將二者的差異,透過從下方

一段話來加以分解:

 

〉WebClient:使用容易,直接使用即可用於擷取或下載Web Service上的資源與內容,甚至支援FTP。

〉HttpWebRequest:使用較複雜,但提供豐富的功能於自訂需要的Header或是其他的資源,協助完成特定工作。

 

的確,WebClient的使用上,其實不用太過於在意Http Header上參數的控制與應用,相對於HttpWebReqeust使用

是非常簡單的(但這不表示WebClient就不能調整需要的Header內容,可透過WebClient的Header屬性來調整需要的Header)。

以上這只是個簡單的分類,實際的使用情境與考慮的因素,我們可以參考以下這一篇的內容:

 

<使用 Silverlight 的 HTTP 通訊和安全性>,我將摘錄其中我覺得比較重要的部分,可以協助剛學習Silverlight時,

可以清楚的理解二者之間的差異性。

 

〉HTTP 通訊情節和建議做法

以下此表主要擷錄<使用 Silverlight 的 HTTP 通訊和安全性>中的"HTTP 通訊情節和建議做法"來加以說明:


序號



情節



建議方式



1



在相同網域中,下載及上載資源。



使用 WebClient 類別。如需詳細資訊,請參閱視需要下載內容。



2



呼叫裝載於相同網域中的 HTTP 架構 Web 服務。



使用 WebClient 類別或 HttpWebRequest/HttpWebResponse 類別。如需詳細資訊,請參閱 HOW TO:對以 HTTP 為基礎的服務發出要求 [SilverLT4]。



3



呼叫裝載於相同網域中的 SOAP、WCF 或 ASP.NET AJAX Web 服務。



呼叫為 Web 服務所產生的 Proxy。如需詳細資訊,請參閱 使用 Proxy 建置和存取服務 [Silverlight]。

如果您不想要使用 Proxy,請使用 HttpWebRequest/HttpWebResponse 類別。



4



處理來自 Web 服務的 XML、JSON 或 RSS 資料。



使用 WebClient 類別或 HttpWebRequest/HttpWebResponse 類別。如需詳細資訊,請參閱直接存取以 HTTP 和 REST 為基礎的服務 [SilverLT4]或 HOW TO:使用 LINQ to XML 從任意 URI 位置載入 XML 檔案。



5



呼叫位於不同網域上的 Web 服務。



確定用戶端存取原則檔位於網域根目錄。使用 Proxy、WebClient 類別或 HttpWebRequest/HttpWebResponse 類別。如需詳細資訊,請參閱 讓服務可跨網域界限使用 [SilverLT4]。



6



傳送 PUT、DELETE 和其他 HTTP 方法,包括自訂方法。



確定用戶端存取原則啟用其他 HTTP 方法。請指定用戶端 HTTP 處理,並依照一般方式使用 HttpWebRequest/HttpWebResponse 類別。如需指定用戶端 HTTP 處理的詳細資訊,請參閱 HOW TO:指定瀏覽器或用戶端 HTTP 處理。



7



對跨網域 POST 要求設定要求標頭。



確定依用戶端存取原則檔允許標頭。

對於有關資料上載的要求標頭,請使用 WebClient 類別。將其 Headers 屬性設定為所需的標頭集合。

針對其他案例,請使用 HttpWebRequest 類別。將其 Headers 屬性設定為所需的標頭集合。如需允許的標頭清單,請參閱 HttpWebRequest.Headers。



8



使用所有方法傳送要求標頭。



請指定用戶端 HTTP 處理,並依照一般方式使用 HttpWebRequest/HttpWebResponse 類別,同時視需要設定 Headers 屬性。



9



傳送要求至傳回錯誤碼和 SOAP 錯誤的 SOAP 服務



請指定用戶端 HTTP 處理,並依照一般方式使用 HttpWebRequest/HttpWebResponse 類別,以擷取發生錯誤的訊息主體。如需指定用戶端 HTTP 處理的詳細資訊,請參閱 HOW TO:指定瀏覽器或用戶端 HTTP 處理。



10



將 GET 要求傳送至需要 Referer 標頭的 Web 服務。



請指定用戶端 HTTP 處理,並依照一般方式使用 HttpWebRequest/HttpWebResponse 類別。如需指定用戶端 HTTP 處理的詳細資訊,請參閱 HOW TO:指定瀏覽器或用戶端 HTTP 處理。


從上表舉出的情境都是在使用WebClient或HttpWebRequest常遇到的,然而你可以從序號:1、2、4與7這四個情境發現,

WebClient使用的情境均比較屬於單純的情境,例如:上傳、下載或常見的Header標題應用。另外:HttpWebReqeust提供的使用情境,

就包括比較豐富的客制Http Header應用,指定的Web Service、WCF或特定Http Method的應用。

上表只能提供一個大概的應用模式。其實還是需要按照開發時遇到的情境為主才能找到適用的方法與內容。

 

另外,更要特別注意Silverlight在於跨網域限制的定義與相對應作業(重點:Silverlight針對不同網域存取時,會先向另一個網域要求

一份"用戶端存取原則檔/跨網域原則檔",根據原則中定義的規格來識別該服務是否支援跨網域的應用)。補充下列幾篇文章有定義

原則檔的說明與安全性定義:<讓服務可跨網域界限使用 [SilverLT4]>與<服務存取的其他安全性考量 [SilverLT4]>。

 

以上是自我整理閱讀WebClient與HttpWebRequest二種類別上的小小心得,因為二者的使用本身也還沒有用的非常深入,只能照目前

閱讀的結果提供一些簡單的歸納。希望能有所幫助。感謝。如果有錯誤,也請多指導。謝謝。