1. Web Service 和 SOAP
XML Web Service 是通過 SOAP(簡單對象訪問協議)協議進行通信的,而 SOAP 消息是利用 XML 進行描述的。使用 XML 描述 SOAP 消息的好處是使得 Web Service 可以跨平臺調用,成就了 Web Service 的巨大魅力。(關于 Web Service 的介紹請看 《XML Web Service 基礎》 )
由于 SOAP 消息是用 XML 進行描述的,如果需要通過 Web Service 傳輸二進制數據,就必須在傳輸之前,將二進制數據轉換成 Base64 編碼的字符串,數據傳送到了接收方后,再將 Base64 編碼的字符串還原為二進制數據。這樣產生了一個問題,經過 Base64 編碼后,二進制數據的體積會膨脹,從而影響了數據傳輸的性能。
2. WSE 和 WS-Attachment
為了解決這個問題,微軟在 Web Service Enhancements (WSE) 中實現了 WS-Attachment 規范,從而避免了在 Web Service 傳輸二進制數據時,需要對二進制數據進行 Base64 編碼/解碼處理。WS-Attachment 的工作原理是將二進制數據作為 SOAP 消息的附件(類似郵件的附件),而不作為 SOAP 消息的內容進行發送。這樣可以避免對二進制數據進行 XML 序列化(XML 序列化過程中會對二進制數據進行 Base64 編碼),因為序列化的只是 SOAP 消息的內容。(關于如何使用 WSE 附件請看 《Using Web Services Enhancements to Send SOAP Messages with Attachments》 )
微軟發布的 WSE 只支持桌面平臺的 .NET Framework,不支持智能設備平臺的 .NET Comapct Framework。如果你想在 Windows Mobile 或 Windows CE 平臺上使用 WS-Attachment 傳輸二進制數據,那就要使用 OpenNETCF SDF 庫了。OpenNETCF SDF 實現了 WSE2 里面大部分的 WS-* 規范,其中包括 WS-Attachment。為 .NET CF 平臺實現這些 WS-* 規范的并非OpenNETCF,而是
brains-N-brawn
。在 OpenNETCF v1.2 之后才加入這部分功能。
3. 在 Windows Mobile 使用 WS-Attachment
我們將通過構建一個上傳和下載文件的應用來展示 WS-Attachment 在 Windows Mobile 上如何使用。構建這個應用我們需要實現一個服務器端和一個客戶端。服務器端也就是 Web Service 端,可以采用 WSE2 SP3 實現 WS-Attachment;客戶端也就是 Windows Mobile 端,采用 OpenNETCF v2.0 實現 WS-Attachment。我們使用 Visual Studio 2005 SP1 開發這個應用。
說到這里,可能對 WSE 比較熟悉的朋友就有疑問了:既然使用 Visual Studio 2005 開發,為什么不用最新的基于 .NET 2.0 的WSE3,而使用基于 .NET 1.1 的 WSE2呢?那是因為 WSE3 已經用一種更好的技術代替 WS-Attchment 了,那就是 MTOM。我也很不理解微軟為什么不在 WSE3 中保留 WS-Attachment,而是直接用 MTOM 將它替換掉。不過慶幸的是 WSE2 SP3 在 Visual Studio 2005 中依然能夠正常工作。
3.1 創建服務器端
1) 打開 Visual Studio 2005,新建一個“ASP.NET Web 服務應用程序”項目,命名為“WSAttachmentService”。如果你找不到這個項目模版,是因為你沒有安裝 Visual Studio 2005 SP1。
2) 為 WSAttachmentService 項目添加引用,在 添加引用 對話框的 .NET 選項卡中,選擇 Microsoft.Web.Service2 (C:\Program Files\Microsoft WSE\v2.0\Microsoft.Web.Services2.dll),并點擊 確定 。
3) 打開 Web.config 文件,添加如下配置項:
< webServices >
< soapExtensionTypes >
< add type ="Microsoft.Web.Services2.WebServicesExtension,Microsoft.Web.Services2,Version=2.0.3.0,Culture=neutral,PublicKeyToken=31BF3856AD364E35" priority ="1" group ="0" />
</ soapExtensionTypes >
</ webServices >
</ system.web >
4) 打開 Service1.asmx.cs 進行代碼編輯,刪除默認的 HelloWorld() Web 方法,并引用3個命名空間。
using Microsoft.Web.Services2;
using Microsoft.Web.Services2.Dime;
5) 添加一個用于下載文件的 Web 方法 DownloadFile()。
public void DownloadFile()
{
SoapContextrespContext = ResponseSoapContext.Current;
DimeAttachmentdimeAttach = new DimeAttachment(
" image/jpg " ,TypeFormat.MediaType,Server.MapPath( " img01.jpg " ));
respContext.Attachments.Add(dimeAttach);
}
6) 再添加一個用于上傳文件的 Web 方法 UploadFile()。
public void UploadFile()
{
SoapContextreqContext = RequestSoapContext.Current;
byte []buffer;
using (Streamstream = reqContext.Attachments[ 0 ].Stream)
{
buffer = new byte [stream.Length];
stream.Read(buffer, 0 ,buffer.Length);
}
// 將數據寫入磁盤文件中(需要設置相應權限)
using (FileStreamfileStream = File.OpenWrite(Server.MapPath( " img02.jpg " )))
{
fileStream.Write(buffer, 0 ,buffer.Length);
}
}
7) 設置 WSAttachmentService 目錄的訪問權限,為 Internet 來賓賬戶添加
修改
和
寫入
權限。
3.2 創建客戶端
1) 在當前解決方案新建一個“Windows Mobile 5.0 Pocket PC”智能設備項目,命名為“WSAttachmentMobile”。
2) 打開 Form1.cs 的窗體設計界面,添加一個 PictureBox 控件(pictureBox1)到 Form1 上,再添加 Download 和 Upload 兩個菜單項(mniDownload 和 mniUpload)。
3) 為項目添加引用,在 添加引用 對話框的 .NET 選項卡中,選擇 OpenNETCF.Web.Service2 (C:\Program Files\OpenNETCF\Smart Device Framework 2.0\OpenNETCF.Web.Services2.dll),并點擊 確定 。
4) 為項目添加 Web 引用,在添加 Web 引用對話框中,輸入 URL 地址: http://localhost/WSAttachmentService/Service.asmx ,點擊地址欄右邊的 前往 按鈕,確認 Web Service 是否能夠打開,然后點擊 添加引用 按鈕。
5) 為項目添加一個類文件 DimeServWrap.cs,代碼如下:
using System.Web.Services.Protocols;
using System.Web.Services.Description;
using OpenNETCF.Web.Services2.Dime;
namespace WSAttachmentMobile
{
public class DimeServWrap:localhost.Service1,IDimeAttachmentContainer
{
public DimeServWrap(): base ()
{
this .Url = " http://bjb-libo/WSAttachmentService/Service1.asmx "
}
DimeAttachmentCollectionrequestAttachments;
DimeAttachmentCollectionresponseAttachments;
// IDimeAttachmentContainer.RequestAttachments
public DimeAttachmentCollectionRequestAttachments
{
get
{
if (requestAttachments == null )
requestAttachments = new DimeAttachmentCollection();
return requestAttachments;
}
}
// IDimeAttachmentContainer.ResponseAttachments
public DimeAttachmentCollectionResponseAttachments
{
get
{
if (responseAttachments == null )
responseAttachments = new DimeAttachmentCollection();
return responseAttachments;
}
}
[DimeExtension]
[SoapDocumentMethod( http://tempuri.org/DownloadFile ,RequestNamespace = " http://tempuri.org/ " ,ResponseNamespace = " http://tempuri.org/ " ,Use = SoapBindingUse.Literal,ParameterStyle = SoapParameterStyle.Wrapped)]
public new void DownloadFile()
{
this .Invoke( " DownloadFile " , new object [ 0 ]);
}
[DimeExtension]
[SoapDocumentMethod( http://tempuri.org/UploadFile ,RequestNamespace = " http://tempuri.org/ " ,ResponseNamespace = " http://tempuri.org/ " ,Use = SoapBindingUse.Literal,ParameterStyle = SoapParameterStyle.Wrapped)]
public new void UploadFile()
{
this .Invoke( " UploadFile " , new object [ 0 ]);
}
}
}
DimeServWrap 類做了幾件事:
a. 繼承了 localhost.Service1 代理類
b. 實現了 OpenNETCF.Web.Services2.Dime.IDimeAttachmentContainer 接口
c. 設置了 Web Service 的 url 地址
d. 覆蓋了基類的 DownloadFile() 和 UploadFile() 方法,并為兩個方法都加上了 DimeExtension 屬性
6) 打開 Form1.cs 代碼進行編輯,并引用兩個命名空間:
using OpenNETCF.Web.Services2.Dime;
7) 回到 Form1 的窗體設計界面,用鼠標雙擊 Download 菜單項,并未 mniDownload 添加 Click 事件的處理代碼:
{
Cursor.Current = Cursors.WaitCursor;
DimeServWrapsvc = new DimeServWrap();
svc.DownloadFile();
byte []buffer;
using (Streamstream = svc.ResponseAttachments[ 0 ].Stream)
{
buffer = new byte [stream.Length];
stream.Read(buffer, 0 ,buffer.Length);
pictureBox1.Image = new Bitmap(stream);
}
using (FileStreamfileStream = File.OpenWrite( " img01.jpg " ))
{
fileStream.Write(buffer, 0 ,buffer.Length);
}
Cursor.Current = Cursors.Default;
MessageBox.Show( " Filewasdownloadedsuccessful! " );
}
8) 采用同樣的方法為 mniUpload 添加 Click 事件的處理代碼:
{
Cursor.Current = Cursors.WaitCursor;
using (FileStreamfileStream = File.OpenRead( " img01.jpg " ))
{
DimeServWrapsvc = new DimeServWrap();
DimeAttachmentdimeAttach = new DimeAttachment(
" uuid: " + Guid.NewGuid().ToString( " D " ), " image/jpg " ,
TypeFormatEnum.MediaType,fileStream);
svc.RequestAttachments.Add(dimeAttach);
svc.UploadFile();
}
Cursor.Current = Cursors.Default;
MessageBox.Show( " Filewasuploadedsuccessful! " );
}
9) 到現在為止,所有代碼已經編寫好了,我們來看看解決方案的文件組織結構,檢查一下是否有遺漏的地方:
3.3 調試程序
1) 從 Visual Studio 2005 的工具菜單打開“設備仿真器管理”,并連接 CHS Windows Mobile 5.0 Pocket PC Emulator (我這里使用的是簡體中文版的設備仿真器鏡像,你也可以使用英文版的),最后將其插入底座,使仿真器可以連接到 ActiveSync,這樣我們的仿真器就能通過網絡訪問到桌面電腦的 Web Service 了。
2) 回到 Visual Studio 2005 中,并在設備工具欄選擇 Windows Mobile 5.0 Pocket PC Device。
3) 接下來我們可以按 F5 鍵開始調試了,在部署過程中會安裝 .NET Compact Framework 2.0 到仿真器中(如果還沒有安裝)。
4) 程序啟動后,先點擊 Download 菜單項,從服務器端下載一個圖片文件,并顯示在窗體上,同時將圖片文件保存到設備上;接著點擊 Upload 菜單項,從設備讀取剛才下載的圖片文件,并上傳到服務器端,服務器端將其保存到根目錄下。
4. 總結
在 Windows Mobile 應用程序中利用 WS-Attachment 傳輸二進制數據,可以減少數據傳輸量,提高數據傳輸速度,從而增強用戶體驗。特別是在 GPRS 和 CDMA 的低速網絡條件下,如果再結合數據壓縮技術,將會取得顯著的效果。不過,如果在局域網的環境下,建議不要對數據進行壓縮。因為局域網的網絡速度足夠快,傳輸大文件和小文件所需要的時間相差不多,而數據壓縮則需要更多的時間,所以速度反而會更慢。畢竟 Windows Mobile 設備的硬件性能是無法跟桌面電腦相比。
示例代碼下載:
WSAttachmentMobile.rar
作者:黎波
博客:http://upto.cnblogs.com/
日期:2007年3月24日
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
