WCF從理論到實踐(7):消息交換模式
系列文章導航:
WCF從理論到實踐(16):操作重載(帶視頻+ppt+源碼)
WCF從理論到實踐(17):OO大背離(帶視頻+ppt+源碼)
本文的出發點
通過閱讀本文,您能理解以下知識:
- WCF定義了哪幾種消息交換模式?
- One-Way Calls
- Request/Reply
- Duplex
- 用示例來解析WCF的消息交換模式
本文適合的讀者
本文涉及到了SOA中的消息交換的基礎概念,需要一些初級的Xml Web Service和分布式系統開發的經驗,最好理解WCF架構
WCF定義了哪幾種消息交換模式?
WCF定義了三種消息交換方式 ,分別為:
- One-Way Calls
- Request/Reply
- Duplex
One-Way Calls
在幾種消息交換模式中,one-way calls是最沒良心的,對于客戶端,one-way calls就如肉包子打狗,有去無回。下面的圖示給出這種交換模型的特征:
在這種交換模式中,存在著如下的特征
- 沒有返回值,返回類型只能為void
- 不能包含ref或者out類型的參數
- 只有客戶端發起請求,服務端并不會對請求進行回復。
通過設置OperationContract的IsOneWay=True可以將滿足要求的方法設置為這種消息交換模式,方法如下:
[OperationContract(IsOneWay=true)]
void Test(int intVal);
上面的代碼,就是將方法Test設置成為了one-way call的消息交換模式,注意如果Test方法的返回類型不是void或者帶有ref或者out類型的參數,都會拋出異常InvalidOperationException,如下面列表中的方法均不能被聲明為one-way模式
int Test(int intVal);
int Test();
int Test();
void Test(ref int intVal);
void Test(out int intVal);
Request/Reply
request/reply比起one-way來說,就更懂得禮尚往來,它是缺省的消息交換模式,類似于http協議中的請求/響應模型。下面的圖示給出這種交換模式的特征:
這種交換模式是使用最多的一中,它有如下特征:
- 調用服務方法后需要等待服務的消息返回,即便該方法返回 void 類型
- 相比Duplex來講,這種模式強調的是客戶端的被動接受,也就是說客戶端接受到響應后,消息交換就結束了。
- 在這種模式下,服務端永遠是服務端,客戶端就是客戶端,職責分明。
它是缺省的消息交換模式,設置OperationContract便可以設置為此種消息交換模式
[OperationContrac]
void Test(int intVal);
注意,盡管Test方法返回為void,但Server也會生成reply響應并發送給client.有來有往是這種模式的特征。
Duplex
這種交換模式比起上面兩種,比較復雜,它和request/reply模式類似,也是有來有往,但處理過程卻比request/reply要復雜,因為它可以在處理完請求之后,通過請求客戶端中的回調進行響應操作,這種模式的圖示為:
注意,這種方式和request/reply方式的圖示也很類似,當二者存在著至關重要的不同,它在客戶端也有監聽節點,在callback的時候,服務器和客戶端的角色會進行交換,服務端此時成了嚴格意義上的客戶端,而客戶端此時能接受服務端的callback請求,所以成為了服務端。呵呵,辯證法,都拗口死了,當事實就是這種,就像對與錯一樣,會相互轉換,失敗是成功之母,而成功是失敗之源。廢話少說,Duplex的特征主要包括
- 消息交換過程中,服務端和客戶端角色會發生調換
- 服務端處理完請求后,返回給客戶端的不是reply,而是callback請求。
打個比方,Reqeust/Reply方式像是搓澡,1個管搓,1個被搓
而duplex像是拳擊,兩個人都會出拳
Duplex模式對Bindding有特殊的要求,它要求支持Duplex MEP(Message Exchange Pattern),如WSDualHttpBinding和NetTcpBinding,有關Binding的介紹請參見http://www.cnblogs.com/jillzhang/archive/2008/02/03/1063406.html
用示例來解析WCF的消息交換模式
建立示例的步驟不做具體闡述,下面看一下項目的最終結構:
下表說明各個項目的作用
項目名稱 |
項目作用 |
包含文件 |
Jillzhang.Messaging.Contract |
定義WCF服務端和客戶端共同使用的Contract接口 |
IOneWayJob.cs INormalJob.cs IJob.cs ICallback.cs |
Jillzhang.Messaging.Service |
實現WCF服務的Contract |
OneWayJob.cs NormalJob.cs Job.cs |
Jillzhang.Messaging.Host |
一個Console應用程序,用于承載WCF服務端 |
Program.cs App.config |
Jillzhang.Messaging.WebSite |
一個用于WebSite,用于承載WCF服務。是例外一中Host |
OnewayService.svc NormalJobService.svc JobService.svc web.config |
Jillzhang.Messaging.Client |
WCF客戶端,一個Console應用程序 |
OnewayProxy.cs NormalJobProxy.cs DuplexProxy.cs MyCallback.cs Program.cs app.config |
下面就看下如何定義消息交換模式為one-way的Contract接口
而IOneWayJob的實現類代碼為:





















Request/reply的Contract接口定義如下:
而INormalJob的實現代碼如下:





























Duplex的交換模式需要現定義Callback的Contract接口,如下:
而服務端的Contract接口為:
Duplex的Contract實現為:

































下面,我們來看一下,如何創建承載服務的應用程序,首先在app.config做如下配置
而Host的代碼如下:
而客戶端的配置文件,如下:

































需要注意的是:在設定Duplex模式時,如果服務端采用的是WsDualHttpBinding,而不是本文中的NetTcpBinding,最好指定以下clientBaseAddress,默認情況下,clientBaseAddress會嘗試用80端口,可通常情況80端口都是被占用,你需要設置一個其他端口。
因為回調的Contract實現是在客戶端的,所以需要在客戶端實現1個ICallback實現,代碼如下:
下面是客戶端調用的代碼:

首先運行服務承載程序Jillzhang.Messaging.Host,然后運行客戶端
會產生如下的結果:
服務端運行解圖
客戶端運行解圖:
本文參考資料
- http://msdn.microsoft.com/msdnmag/issues/06/10/wcfessentials/default.aspx
- http://www.rainsts.net/article.asp?id=428
本文相關示例文件