WCF從理論到實(shí)踐(7):消息交換模式
本文的出發(fā)點(diǎn)
通過閱讀本文,您能理解以下知識(shí):
- WCF定義了哪幾種消息交換模式?
- One-Way Calls
- Request/Reply
- Duplex
- 用示例來解析WCF的消息交換模式
本文適合的讀者
本文涉及到了SOA中的消息交換的基礎(chǔ)概念,需要一些初級(jí)的Xml Web Service和分布式系統(tǒng)開發(fā)的經(jīng)驗(yàn),最好理解WCF架構(gòu)
WCF定義了哪幾種消息交換模式?
WCF定義了三種消息交換方式 ,分別為:
- One-Way Calls
- Request/Reply
- Duplex
One-Way Calls
在幾種消息交換模式中,one-way calls是最沒良心的,對(duì)于客戶端,one-way calls就如肉包子打狗,有去無回。下面的圖示給出這種交換模型的特征:
在這種交換模式中,存在著如下的特征
- 沒有返回值,返回類型只能為void
- 不能包含ref或者out類型的參數(shù)
- 只有客戶端發(fā)起請(qǐng)求,服務(wù)端并不會(huì)對(duì)請(qǐng)求進(jìn)行回復(fù)。
通過設(shè)置OperationContract的IsOneWay=True可以將滿足要求的方法設(shè)置為這種消息交換模式,方法如下:
[OperationContract(IsOneWay=true)]
void Test(int intVal);
上面的代碼,就是將方法Test設(shè)置成為了one-way call的消息交換模式,注意如果Test方法的返回類型不是void或者帶有ref或者out類型的參數(shù),都會(huì)拋出異常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協(xié)議中的請(qǐng)求/響應(yīng)模型。下面的圖示給出這種交換模式的特征:
這種交換模式是使用最多的一中,它有如下特征:
- 調(diào)用服務(wù)方法后需要等待服務(wù)的消息返回,即便該方法返回 void 類型
- 相比Duplex來講,這種模式強(qiáng)調(diào)的是客戶端的被動(dòng)接受,也就是說客戶端接受到響應(yīng)后,消息交換就結(jié)束了。
- 在這種模式下,服務(wù)端永遠(yuǎn)是服務(wù)端,客戶端就是客戶端,職責(zé)分明。
它是缺省的消息交換模式,設(shè)置OperationContract便可以設(shè)置為此種消息交換模式
[OperationContrac]
void Test(int intVal);
注意,盡管Test方法返回為void,但Server也會(huì)生成reply響應(yīng)并發(fā)送給client.有來有往是這種模式的特征。
Duplex
這種交換模式比起上面兩種,比較復(fù)雜,它和request/reply模式類似,也是有來有往,但處理過程卻比request/reply要復(fù)雜,因?yàn)樗梢栽谔幚硗暾?qǐng)求之后,通過請(qǐng)求客戶端中的回調(diào)進(jìn)行響應(yīng)操作,這種模式的圖示為:
注意,這種方式和request/reply方式的圖示也很類似,當(dāng)二者存在著至關(guān)重要的不同,它在客戶端也有監(jiān)聽節(jié)點(diǎn),在callback的時(shí)候,服務(wù)器和客戶端的角色會(huì)進(jìn)行交換,服務(wù)端此時(shí)成了嚴(yán)格意義上的客戶端,而客戶端此時(shí)能接受服務(wù)端的callback請(qǐng)求,所以成為了服務(wù)端。呵呵,辯證法,都拗口死了,當(dāng)事實(shí)就是這種,就像對(duì)與錯(cuò)一樣,會(huì)相互轉(zhuǎn)換,失敗是成功之母,而成功是失敗之源。廢話少說,Duplex的特征主要包括
- 消息交換過程中,服務(wù)端和客戶端角色會(huì)發(fā)生調(diào)換
- 服務(wù)端處理完請(qǐng)求后,返回給客戶端的不是reply,而是callback請(qǐng)求。
打個(gè)比方,Reqeust/Reply方式像是搓澡,1個(gè)管搓,1個(gè)被搓
而duplex像是拳擊,兩個(gè)人都會(huì)出拳
Duplex模式對(duì)Bindding有特殊的要求,它要求支持Duplex MEP(Message Exchange Pattern),如WSDualHttpBinding和NetTcpBinding,有關(guān)Binding的介紹請(qǐng)參見http://www.rzrgm.cn/jillzhang/archive/2008/02/03/1063406.html
用示例來解析WCF的消息交換模式
建立示例的步驟不做具體闡述,下面看一下項(xiàng)目的最終結(jié)構(gòu):
下表說明各個(gè)項(xiàng)目的作用
|
項(xiàng)目名稱 |
項(xiàng)目作用 |
包含文件 |
|
Jillzhang.Messaging.Contract |
定義WCF服務(wù)端和客戶端共同使用的Contract接口 |
IOneWayJob.cs INormalJob.cs IJob.cs ICallback.cs |
|
Jillzhang.Messaging.Service |
實(shí)現(xiàn)WCF服務(wù)的Contract |
OneWayJob.cs NormalJob.cs Job.cs |
|
Jillzhang.Messaging.Host |
一個(gè)Console應(yīng)用程序,用于承載WCF服務(wù)端 |
Program.cs App.config |
|
Jillzhang.Messaging.WebSite |
一個(gè)用于WebSite,用于承載WCF服務(wù)。是例外一中Host |
OnewayService.svc NormalJobService.svc JobService.svc web.config |
|
Jillzhang.Messaging.Client |
WCF客戶端,一個(gè)Console應(yīng)用程序 |
OnewayProxy.cs NormalJobProxy.cs DuplexProxy.cs MyCallback.cs Program.cs app.config |
下面就看下如何定義消息交換模式為one-way的Contract接口
而IOneWayJob的實(shí)現(xiàn)類代碼為:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jillzhang.Messaging.Contract;
namespace Jillzhang.Messaging.Service
{
public class OneWayJob : IOneWayJob
{
public void Do(string jobName)
{
System.Diagnostics.Stopwatch watcher = new System.Diagnostics.Stopwatch();
watcher.Start();
System.Threading.Thread.Sleep(1000);
Console.WriteLine("服務(wù)" + AppDomain.CurrentDomain.FriendlyName + "執(zhí)行任務(wù):" + jobName);
watcher.Stop();
}
}
}
Request/reply的Contract接口定義如下:
而INormalJob的實(shí)現(xiàn)代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jillzhang.Messaging.Contract;
namespace Jillzhang.Messaging.Service
{
public class NormalJob:INormalJob
{
public string Do(string jobName)
{
try
{
System.Diagnostics.Stopwatch watcher = new System.Diagnostics.Stopwatch();
watcher.Start();
System.Threading.Thread.Sleep(1000);
Console.WriteLine("服務(wù)" + AppDomain.CurrentDomain.FriendlyName + "執(zhí)行任務(wù):" + jobName);
watcher.Stop();
return "成功";
}
catch
{
return "失敗";
}
}
}
}
Duplex的交換模式需要現(xiàn)定義Callback的Contract接口,如下:
而服務(wù)端的Contract接口為:
Duplex的Contract實(shí)現(xiàn)為:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jillzhang.Messaging.Contract;
using System.ServiceModel;
namespace Jillzhang.Messaging.Service
{
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class Job:IJob
{
public string Do(string jobName)
{
try
{
ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
System.Diagnostics.Stopwatch watcher = new System.Diagnostics.Stopwatch();
watcher.Start();
System.Threading.Thread.Sleep(1000);
Console.WriteLine("服務(wù)" + AppDomain.CurrentDomain.FriendlyName + "執(zhí)行任務(wù):" + jobName);
watcher.Stop();
callback.Done((int)watcher.ElapsedMilliseconds);
return "成功";
}
catch
{
return "失敗";
}
}
}
}
下面,我們來看一下,如何創(chuàng)建承載服務(wù)的應(yīng)用程序,首先在app.config做如下配置
而Host的代碼如下:
而客戶端的配置文件,如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="netTcpBinding" />
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:6987/Service/duplex" binding="netTcpBinding"
bindingConfiguration="netTcpBinding" contract="Jillzhang.Messaging.Contract.IJob"
name="NetTcpBinding">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="net.tcp://localhost:6987/Service/oneway" binding="netTcpBinding"
bindingConfiguration="netTcpBinding" contract="Jillzhang.Messaging.Contract.IOneWayJob"
name="NetTcpBinding">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="net.tcp://localhost:6987/Service/normal" binding="netTcpBinding"
bindingConfiguration="netTcpBinding" contract="Jillzhang.Messaging.Contract.INormalJob"
name="NetTcpBinding">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
需要注意的是:在設(shè)定Duplex模式時(shí),如果服務(wù)端采用的是WsDualHttpBinding,而不是本文中的NetTcpBinding,最好指定以下clientBaseAddress,默認(rèn)情況下,clientBaseAddress會(huì)嘗試用80端口,可通常情況80端口都是被占用,你需要設(shè)置一個(gè)其他端口。
因?yàn)榛卣{(diào)的Contract實(shí)現(xiàn)是在客戶端的,所以需要在客戶端實(shí)現(xiàn)1個(gè)ICallback實(shí)現(xiàn),代碼如下:
下面是客戶端調(diào)用的代碼:
首先運(yùn)行服務(wù)承載程序Jillzhang.Messaging.Host,然后運(yùn)行客戶端
會(huì)產(chǎn)生如下的結(jié)果:
服務(wù)端運(yùn)行解圖
客戶端運(yùn)行解圖:
本文參考資料
- http://msdn.microsoft.com/msdnmag/issues/06/10/wcfessentials/default.aspx
- http://www.rainsts.net/article.asp?id=428
本文相關(guān)示例文件
示例項(xiàng)目:/Files/jillzhang/Jillzhang.Messaging.rar
出處:http://jillzhang.cnblogs.com/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。

通過閱讀本文,您能理解以下知識(shí):
1) WCF定義了哪幾種消息交換模式?
2) One-Way Calls
3) Request/Reply
4) Duplex
5) 用示例來解析WCF的消息交換模式


浙公網(wǎng)安備 33010602011771號(hào)