WCF學(xué)習(xí):Instance context model(實(shí)例模型) 與 Session(會(huì)話) 的關(guān)系
在WCF中對(duì)Session是默認(rèn)支持的,但是和ASP.NET中的支持完全不同,說(shuō)到Session,那么肯定有服務(wù)端(Service)和客戶端(Client),客戶端通過(guò)代理(Proxy)來(lái)訪問(wèn)服務(wù)端,所以Session的周期和Proxy的周期綁定。對(duì)分布式的程序而言,根據(jù)業(yè)務(wù)的要求,我們會(huì)有三種需求:
第一:服務(wù)端不用保存客戶端的狀態(tài),每次客戶端的訪問(wèn)都是獨(dú)立的;
第二:服務(wù)端需要保持客戶端的狀態(tài),每次客服端的請(qǐng)求會(huì)用到同一個(gè)Session;
第三:在多用戶中共享同一個(gè)實(shí)例(其實(shí)這里類似ASP.NET中的Application,但完全不一樣)。
下面我們就針對(duì)上述的三種要求,分享一下再WCF中的實(shí)現(xiàn)方式. 以及各種實(shí)現(xiàn)方式的優(yōu)勢(shì)和缺點(diǎn)。對(duì)上述三種使用場(chǎng)景,WCF已經(jīng)提供了良好的支持,這就是Instancing Management。具體是實(shí)現(xiàn)方式是:Instance context model?梢赃@么說(shuō),Instance Context Mode決定著不同的Session表現(xiàn)。WCF中有三種 Instance Context Mode,他們分別是:
>> Per-Call:每次的客戶端請(qǐng)求分配一個(gè)新的服務(wù)實(shí)例。 類似于Net Remoting的SingleCall模式, 在這種方式下,程序的擴(kuò)展性是最強(qiáng)的,在事務(wù)編程與隊(duì)列服務(wù)中優(yōu)勢(shì)更為明顯。但是由于頻繁地創(chuàng)建與銷毀實(shí)例,會(huì)對(duì)性能造成一定的影響。當(dāng)然網(wǎng)上的牛人,已經(jīng)考慮到使用線程池的方式來(lái)減少頻繁地創(chuàng)建與銷毀實(shí)例(參考地址:http://www.cnblogs.com/artech/archive/2008/08/05/1260594.html)
>> PerSession: 服務(wù)端需要保持客戶端的狀態(tài),為每次客戶端連接分配一個(gè)服務(wù)實(shí)例,客戶端的每次調(diào)用,會(huì)使用到同一個(gè)實(shí)例,如果實(shí)例銷毀,客戶端的調(diào)用會(huì)拋出異常。類似于Net Remoting的客戶端激活模式;這是wcf的默認(rèn)支持方式. 由于每個(gè)客戶端都需要維護(hù)一個(gè)會(huì)話,需要占用較多的資源來(lái)保存服務(wù)會(huì)話狀態(tài)。如果存在多個(gè)獨(dú)立的客戶端,則創(chuàng)建專門的服務(wù)實(shí)例的代價(jià)太大。
>> Singleton: 所有客戶端而言,都只有一個(gè)服務(wù)實(shí)例,當(dāng)服務(wù)端被host的時(shí)候,就會(huì)創(chuàng)建,有且僅有一個(gè)服務(wù)實(shí)例來(lái)響應(yīng)客戶端服務(wù)調(diào)用的請(qǐng)求,在多個(gè)客戶端請(qǐng)求下,服務(wù)端只會(huì)處理一個(gè)客戶端的請(qǐng)求,其他的排隊(duì)等候處理。因此在系統(tǒng)的吞吐量、相應(yīng)效率、系統(tǒng)服務(wù)性能上都存在嚴(yán)重的瓶頸
好處是,可以共享數(shù)據(jù).
特別的強(qiáng)調(diào)兩點(diǎn):
第一:上述三種 Instance context model ,但是并不是所有的Binding都支持 Session ,對(duì)Per-Call和Singleton而言,binding影響不大。對(duì)PerSession,就必須使用特定的Binding, 才可以,否則最終指向的是PerCall,見(jiàn)下表:
Binding | Session mode | Context mode | Async Dispose() | Instance mode |
---|---|---|---|---|
Basic | Allowed/NotAllowed | PerCall/PerSession | Yes | PerCall |
TCP, IPC | Allowed/Required | PerCall | No | PerCall |
TCP, IPC | Allowed/Required | PerSession | Yes | PerSession |
WS (no security, no reliability) | NotAllowed/Allowed | PerCall/PerSession | Yes | PerCall |
WS (with security or reliability) | Allowed/Required | PerSession | Yes | PerSession |
WS (with security or reliability) | NotAllowed | PerCall/PerSession | Yes | PerCall |
第二:由于PerSession, 為每次客戶端連接分配一個(gè)服務(wù)實(shí)例,會(huì)消耗服務(wù)器的資源,所以可以把PerSession和PerCall結(jié)合使用。在特定的條件下我們完全可以在客戶端的Message中包括特定的用戶****來(lái),請(qǐng)求PerCall,來(lái)代替每次請(qǐng)求PerSession。當(dāng)然這是在特定的情況下。
下面來(lái)看具體的執(zhí)行代碼:
1、建立服務(wù)契約
public interface IInstanceContextMode
{
//操作契約
[OperationContract]
void SayHello();
}
#region PerCall
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]public class WCFServicePerCall : IInstanceContextMode, IDisposable
{
//服務(wù)實(shí)例計(jì)數(shù)
private int mCcount = 0;
//構(gòu)造函數(shù)
public WCFServicePerCall()
{
Console.WriteLine("WCFServicePerCall Instance is Created ");
}
//實(shí)現(xiàn)接口定義的方法
public void SayHello()
{
mCcount++;
Console.WriteLine("WCFServicePerCall Instance Count is: {0} ", mCcount);
}
//實(shí)現(xiàn)接口定義的方法Dispose
public void Dispose()
{
Console.WriteLine("WCFServicePerCall Instance is disposed ");
}
}
#endregion
#region PerSession
//3.服務(wù)類.會(huì)話服務(wù)
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class WCFServicePerSession : IInstanceContextMode
{
//服務(wù)實(shí)例計(jì)數(shù)
private int mCcount = 0;
//構(gòu)造函數(shù)
public WCFServicePerSession()
{
Console.WriteLine("WCFServicePerSession Instance is Created ");
}
//實(shí)現(xiàn)接口定義的方法
public void SayHello()
{
mCcount++;
Console.WriteLine("WCFServicePerSession Instance Count is: {0} ", mCcount);
}
//實(shí)現(xiàn)接口定義的方法Dispose
public void Dispose()
{
Console.WriteLine("WCFServicePerSession Instance is disposed ");
}
}
#endregion
#region Single
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class WCFServiceSingleTon : IInstanceContextMode
{
//服務(wù)實(shí)例計(jì)數(shù)
private int mCcount = 0;
//構(gòu)造函數(shù)
public WCFServiceSingleTon()
{
Console.WriteLine("WCFServiceSingleTon Instance is Created ");
}
//實(shí)現(xiàn)接口定義的方法
public void SayHello()
{
mCcount++;
Console.WriteLine("WCFServiceSingleTon Instance Count is: {0} ", mCcount);
}
//實(shí)現(xiàn)接口定義的方法Dispose
public void Dispose()
{
Console.WriteLine("WCFServiceSingleTon Instance is disposed ");
}
}
#endregion
第三:服務(wù)端的配置文件
<serviceBehaviors>
<behavior name="DefaultBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceThrottling maxConcurrentCalls="100" maxConcurrentSessions="100" maxConcurrentInstances="100" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Fish.ServiceImpl.WCFServicePerCall">
<endpoint address="" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<endpoint address="" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/Fish/WCFServicePerCall/>
<add baseAddress="net.tcp://localhost:808/Fish/WCFServicePerCall"/>
</baseAddresses>
</host>
</service>
<service name="Fish.ServiceImpl.WCFServicePerSession">
<endpoint address="" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<endpoint address="" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:808/Fish/WCFServicePerSession"/>
<add baseAddress="http://localhost:8080/Fish/WCFServicePerSession/>
</baseAddresses>
</host>
</service>
<service behaviorConfiguration="DefaultBehavior" name="Fish.ServiceImpl.WCFServiceSingleTon">
<endpoint address="" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<endpoint address="" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode"></endpoint>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:808/Fish/WCFServiceSingleTon"/>
<add baseAddress="http://localhost:8080/Fish/WCFServiceSingleTon/>
</baseAddresses>
</host>
</service>
第四:Host
class Program
{
static void Main(string[] args)
{
try
{
List<ServiceHost> hosts = new List<ServiceHost>();
hosts.Add(new ServiceHost(typeof(WCFServicePerCall))); //PerCall
hosts.Add(new ServiceHost(typeof(WCFServicePerSession))); //PerSession
hosts.Add(new ServiceHost(typeof(WCFServiceSingleTon))); //SingleTon
hosts.ForEach(host => host.Open());
Console.WriteLine("All services are started...");
Console.Read();
}
catch(Exception e)
{
Console.WriteLine("錯(cuò)誤信息是:"+e.ToString());
}
}
}
class Program
{
static void Main(string[] args)
{
PerCall();
PerSession();
Single();
Console.WriteLine(" ");
}
#region PerCall
private static void PerCall()
{
var perCall = new ChannelFactory<IInstanceContextMode>("tcpPerCall").CreateChannel();
perCall.SayHello();
perCall.SayHello();
perCall.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(perCall);
var tcpPerCall = new ChannelFactory<IInstanceContextMode>("tcpPerCall").CreateChannel();
tcpPerCall.SayHello();
tcpPerCall.SayHello();
tcpPerCall.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(tcpPerCall);
}
#endregion
#region PerSession
private static void PerSession()
{
var perSession = new ChannelFactory<IInstanceContextMode>("basicHttpPerSession").CreateChannel();
perSession.SayHello();
perSession.SayHello();
perSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(perSession);
var tcpPerSession = new ChannelFactory<IInstanceContextMode>("tcpPerSession").CreateChannel();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(tcpPerSession);
}
#endregion
#region Single
private static void Single()
{
var perSession = new ChannelFactory<IInstanceContextMode>("basicHttpSingleTon").CreateChannel();
perSession.SayHello();
perSession.SayHello();
perSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(perSession);
var tcpPerSession = new ChannelFactory<IInstanceContextMode>("tcpSingleTon").CreateChannel();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
tcpPerSession.SayHello();
ServiceBroker.DisposeService<IInstanceContextMode>(tcpPerSession);
}
#endregion
}
<endpoint name="httpPerCall" address="http://localhost:8080/Fish/WCFServicePerCall" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="tcpPerCall" address="net.tcp://localhost:808/Fish/WCFServicePerCall" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="basicHttpPerSession" address="http://localhost:8080/Fish/WCFServicePerSession" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="tcpPerSession" address="net.tcp://localhost:808/Fish/WCFServicePerSession" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="basicHttpSingleTon" address="http://localhost:8080/Fish/WCFServiceSingleTon" binding="basicHttpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
<endpoint name="tcpSingleTon" address="net.tcp://localhost:808/Fish/WCFServiceSingleTon" binding="netTcpBinding" contract="Fish.ServiceInterfaces.IInstanceContextMode" ></endpoint>
</client>