WCF服务实例激活类型编程与开发(转)
【引言】:
?? 在WCF分布式開發(fā)必備知識(2):.Net Remoting這 篇文章里我已經(jīng)介紹過了Net Remoting相關的概念,其中也包括Net Remoting的激活方式:SingleTon模式、SingleCall模式、客戶端激活方式。其實WCF服務的激活方式也與此相似。服務激活方式也 是WCF借鑒Net Remoting的一個明顯的例子。Net Remoting相關的概念大家可以查閱WCF分布式開發(fā)必備知識(2):.Net Remoting這篇文章。 下面我們就來詳細的介紹WCF服務激活類型相關的知識點。首先來介紹的是單調(diào)服務。
??? WCF支持三種實例激活的類型:
1>.單調(diào)服務(Per-Call Service):每次的客戶端請求分配一個新的服務實例。類似于Net Remoting的SingleCall模式;
2>.會話服務(Sessionful Service):則為每次客戶端連接分配一個服務實例。類似于Net Remoting的客戶端激活模式;
3>.單例服務(Singleton Service):所有的客戶端會為所有的連接和激活對象共享一個相同的服務實例。類似于Net Remoting的SingleTon模式。
?? 這里的服務激活模式是由我們定義的服務的上下文模式InstanceContextMode
屬性來配置的,其代碼如下:
{
????PerSession,
????PerCall,
????Single
}
?【1】單調(diào)服務(Call Service):
【1.1】基本概念
?? 單調(diào)服務(Per-Call Service):每次的客戶端請求分配一個新的服務實例。服務實例的生存周期緊緊限制于一次調(diào)用的開始與結束之間。客戶端的每次請求都會產(chǎn)生新的服務實 例來響應這個調(diào)用。類似于Net Remoting的SingleCall模式。 執(zhí)行步驟如下:
1. 客戶端調(diào)用代理,代理將調(diào)用轉(zhuǎn)發(fā)給服務。
2. WCF創(chuàng)建一個服務實例,然后調(diào)用服務實例的方法。
3. 當方法調(diào)用返回時,如果對象實現(xiàn)了IDisposable接口,WCF將調(diào)用IDisposable.Dispose()方法。
4. 客戶端調(diào)用代理,代理將調(diào)用轉(zhuǎn)發(fā)給服務。
5. WCF創(chuàng)建一個對象,然后調(diào)用對象的方法。
????????????????????????????????????????????????????????? 單調(diào)服務的實例化模型圖:
??
【1.2】開發(fā)配置:
??? 單調(diào)服務開發(fā)配置十分簡單,我們使用[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]配置服務屬性完成。這樣的WCF服務模式為單調(diào)模式,WCF框架對自動更具設置的屬性 來決定具體的服務激活類型。代碼如下所示:
????public?class?WCFServicePerCall?:?IWCFService,IDisposable
????{
????}
?【1.3】注意:
??? (1)[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]特性只能應用到類上。
??? (2) 如果使用了昂貴的資源,如數(shù)據(jù)庫連接等非托管資源,繼承IDisposable接口,??????? //實現(xiàn)接口定義的方法Dispose()方法顯示釋放資源。但是也有弊端,頻繁地創(chuàng)建與銷毀實例,仍然會對性能造成一定的影響。?
??? (3)對于WCF服務而言,單調(diào)服務可以算是最佳的實例激活模式。? 單調(diào)服務的一個最重要優(yōu)勢在于它能夠節(jié)省資源,支持系統(tǒng)的可伸縮性。另外在事務編程與隊列服務中優(yōu)勢更為明顯,在事務編程中新建服務實例,減少實例狀態(tài)的 同步;而消息隊列,單調(diào)服務能夠建立服務實例與隊列消息之間的簡單映射。詳細信息會在后續(xù)文章中介紹。
【2】會話服務(Sessionful Service):
【2.1】基本概念:
??? 會話服務(Sessionful Service):則為每次客戶端連接分配一個服務實例。類似于Net Remoting的客戶端激活模式。為每個客戶端創(chuàng)建一個專門的服務實例。只要會話沒有結束,該實例就不會被銷毀。?對于會話服務而言,是一個客戶端代理 對應一個服務實例。也就是說,會話服務中的服務是與代理相對應的,而不是對應于一個客戶端。
【2.2】配置開發(fā):
??? 服務實例的默認激活方式為會話服務模式。我們也可以顯示配置會話服務的方式,使用[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)],具體代碼如下所示:
?
//3.服務類.會話服務????[ServiceBehavior(InstanceContextMode?=?InstanceContextMode.PerSession)]
????public?class?WCFServicePerSession?:?IWCFService
????{
????}
??? 服務配置[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]之后,需要在服務契約一級配置 [ServiceContract(SessionMode=SessionMode.Allowed)],服務元數(shù)據(jù)將包含SessionMode值。 客戶端的WCF反序列化后會包含此信息,來確定服務是否使用了會話模式,SessionMode為枚舉類型:
public?enum?SessionMode{
Allowed,
Required,
NotAllowed
}?
?? 不是所有的綁定協(xié)議都支持會話傳輸模式,TCP協(xié)議為傳輸控制協(xié)議,會與客戶端維護一個連接。而HTTP為無連接狀態(tài),我們無法保證其與客戶端的會話連接。
【2.3】注意:
(1)會話服務存在可伸縮性的問題。由于每個客戶端都需要維護一個會話,需要占用較多的資源來保存服務會話狀態(tài)。如果存在多個獨立的客戶端,則創(chuàng)建專門的服務實例的代價太大。?
(2)WCF服務綁定協(xié)議與會話特性之間的關系見下表:
| 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 |
(3) 應該避免將單調(diào)服務與會話契約混合定義在相同的會話服務類型中,會話應該保證是可靠的,一個實現(xiàn)了會話契約的服務,它包含的所有終結點所公開的契約都應該使用支持可靠傳輸會話的綁定。?
(4) InactivityTimeout可以配置一個新的空閑超時值,服務實例空閑時間超過這個范圍時候就會終止會話。InactivityTimeout屬 性的默認值為10分鐘。不能將該值設置為小于或等于0的值,否則會拋出ArgumentOutOfRangeException異常。
【3】單例服務(Singleton Service):
【3.1】基本概念:
??? 設計模式中最簡單和容易理解的就是單例(單件)模式(SingleTon),單例服務(Singleton Service)也是一種單件模式的實踐應用的例子。單例服務(Singleton Service)就是針對所有客戶端而言,都只有一個服務實例。單例服務的生存期是不受GC管理,不會終止,只有在關閉宿主時,才會被釋放。創(chuàng)建宿主時, 單例服務的實例就會被創(chuàng)建(這個可以再托管宿主的監(jiān)控狀態(tài)信息中得到證實,宿主運行時候,單例服務的已經(jīng)顯示實例化完畢,而單調(diào)服務和會話服務實例尚未啟 動),并且只能被創(chuàng)建一次,一直運行下去,有且僅有一個服務實例來響應客戶端服務調(diào)用的請求。
??
【3.2】配置與開發(fā):
??? 服務實例的單調(diào)激活模式可以通過[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]配置完成,具體的代碼如下:
????public?class?WCFServiceSingleTon?:?IWCFService
????{
????}
【3.3】注意:
(1)單例服務同一時間內(nèi)只能相應一個客戶端請求。因此在系統(tǒng)的吞吐量、相應效率、系統(tǒng)服務性能上都存在嚴重的瓶頸。
【4】示例代碼分析:
??? 下面我們來介紹本次的示例代碼,這里我們分別定義了三種激活類型的服務類:單調(diào)服務(Per-Call Service),會話服務(Sessionful Service),單例服務(Singleton Service),托管宿主分別進行托管,這里為了測試,我們使用的綁定協(xié)議也是TCP方式,其他的協(xié)議這里沒做具體的實現(xiàn),有興趣的朋友可以自己擴展修 改代碼,進行測試。
【4.1】服務端:
??? ,定義了一個服務契約,一個操作SayHello(),具體的服務類型定義和激活類型配置如下:
?
//此例定義了一個服務契約,三種服務分別為單調(diào)服務、會話服務、單例服務或單件服務namespace?WCFService
{
????//1.服務契約
????[ServiceContract(SessionMode=SessionMode.Allowed,?Namespace?=?"http://www.cnblogs.com/frank_xl/")]
????public?interface?IWCFService
????{
????????//操作契約
????????[OperationContract]
????????void?SayHello();
????}
????//2.服務類.單調(diào)服務
????[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
????public?class?WCFServicePerCall?:?IWCFService,IDisposable
????{
????????//服務實例計數(shù)
????????private?int?mCcount?=0;
????????//構造函數(shù)
????????public?WCFServicePerCall()
????????{
????????????Console.WriteLine("WCFServicePerCall?Instance?is?Created?");
????????}
????????//實現(xiàn)接口定義的方法
????????public?void?SayHello()
????????{
????????????mCcount++;
????????????Console.WriteLine("WCFServicePerCall?Instance?Count?is:?{0}?",mCcount);
????????}
????????//實現(xiàn)接口定義的方法Dispose
????????public?void?Dispose()
????????{
????????????Console.WriteLine("WCFServicePerCall?Instance?is?disposed?");
????????}
????}
????//3.服務類.會話服務
????[ServiceBehavior(InstanceContextMode?=?InstanceContextMode.PerSession)]
????public?class?WCFServicePerSession?:?IWCFService
????{
????????//服務實例計數(shù)
????????private?int?mCcount?=?0;
????????//構造函數(shù)
????????public?WCFServicePerSession()
????????{
????????????Console.WriteLine("WCFServicePerSession?Instance?is?Created?");
????????}
????????//實現(xiàn)接口定義的方法
????????public?void?SayHello()
????????{
????????????mCcount++;
????????????Console.WriteLine("WCFServicePerSession?Instance?Count?is:?{0}?",?mCcount);
????????}
????????//實現(xiàn)接口定義的方法Dispose
????????public?void?Dispose()
????????{
????????????Console.WriteLine("WCFServicePerSession?Instance?is?disposed?");
????????}
????}
????//4.服務類.單例服務
????[ServiceBehavior(InstanceContextMode?=?InstanceContextMode.Single)]
????public?class?WCFServiceSingleTon?:?IWCFService
????{
????????//服務實例計數(shù)
????????private?int?mCcount?=?0;
????????//構造函數(shù)
????????public?WCFServiceSingleTon()
????????{
????????????Console.WriteLine("WCFServiceSingleTon?Instance?is?Created?");
????????}
????????//實現(xiàn)接口定義的方法
????????public?void?SayHello()
????????{
????????????mCcount++;
????????????Console.WriteLine("WCFServiceSingleTon?Instance?Count?is:?{0}?",?mCcount);
????????}
????????//實現(xiàn)接口定義的方法Dispose
????????public?void?Dispose()
????????{
????????????Console.WriteLine("WCFServiceSingleTon?Instance?is?disposed?");
????????}
????}
}
【4.2】宿主:
??? 針對三種激活類型的服務分別定義了三個宿主實例:hostWCFServicePerCall、hostWCFServicePerSession、hostWCFServiceSingleTon。測試完畢,關閉宿主。代碼具體如下:
//采用自托管方式,也可以是IIS、WAS,Windows服務等用戶自定義程序托管服務???public?class?WCFHost
????{
????????static?void?Main(string[]?args)
????????{
????????????//1.單調(diào)服務WCFServicePerCall
????????????ServiceHost?hostWCFServicePerCall?=?new?ServiceHost(typeof(WCFService.WCFServicePerCall));
????????????//判斷是否以及打開連接,如果尚未打開,就打開偵聽端口
????????????if?(hostWCFServicePerCall.State?!=?CommunicationState.Opening)
????????????????hostWCFServicePerCall.Open();
????????????//顯示運行狀態(tài)
????????????Console.WriteLine("WCFServicePerCall?Host?is?runing!?and?state?is?{0}",?hostWCFServicePerCall.State);
????????????//2.會話服務WCFServicePerSession
????????????ServiceHost?hostWCFServicePerSession?=?new?ServiceHost(typeof(WCFService.WCFServicePerSession));
????????????
????????????//判斷是否以及打開連接,如果尚未打開,就打開偵聽端口
????????????if?(hostWCFServicePerSession.State?!=?CommunicationState.Opening)
????????????????hostWCFServicePerSession.Open();
????????????//顯示運行狀態(tài)
????????????Console.WriteLine("WCFServicePerSession?Host?is?runing!?and?state?is?{0}",?hostWCFServicePerSession.State);
????????????//3.單例服務WCFServiceSingleTon
????????????ServiceHost?hostWCFServiceSingleTon?=?new?ServiceHost(typeof(WCFService.WCFServiceSingleTon));
????????????????//判斷是否以及打開連接,如果尚未打開,就打開偵聽端口
????????????if?(hostWCFServiceSingleTon.State?!=?CommunicationState.Opening)
????????????????hostWCFServiceSingleTon.Open();
????????????//顯示運行狀態(tài)
????????????Console.WriteLine("WCFServiceSingleTon?Host?is?runing!?and?state?is?{0}",?hostWCFServiceSingleTon.State);
????????????//等待輸入即停止服務
????????????Console.Read();
????????????//4?Close?Host
????????????hostWCFServicePerCall.Close();
????????????hostWCFServicePerSession.Close();
????????????hostWCFServiceSingleTon.Close();
????????}
??? 綁定協(xié)議這里使用的是TCP,三個服務分別配置了服務的終結點,包括契約、地址、綁定。元數(shù)據(jù)交換節(jié)點也進行了配置。具體配置文件如下:
<service?behaviorConfiguration="WCFService.WCFServiceBehavior"?name="WCFService.WCFServicePerCall">
????????<endpoint
??????????address="net.tcp://localhost:9001/WCFServicePerCall"
??????????binding="netTcpBinding"
??????????contract="WCFService.IWCFService">
????????</endpoint>
????????<endpoint?address="mex"?binding="mexTcpBinding"?contract="IMetadataExchange"?/>
????????<host>
??????????<baseAddresses>
????????????<add?baseAddress="net.tcp://localhost:9001/"/>
??????????</baseAddresses>
????????</host>
??????</service>
??????<service?behaviorConfiguration="WCFService.WCFServiceBehavior"?name="WCFService.WCFServicePerSession">
????????<endpoint
??????????address="net.tcp://localhost:9002/WCFServicePerSession"
??????????binding="netTcpBinding"
??????????contract="WCFService.IWCFService">
????????</endpoint>
????????<endpoint?address="mex"?binding="mexTcpBinding"?contract="IMetadataExchange"?/>
????????<host>
??????????<baseAddresses>
????????????<add?baseAddress="net.tcp://localhost:9002/"/>
??????????</baseAddresses>
????????</host>
??????</service>
??????<service?behaviorConfiguration="WCFService.WCFServiceBehavior"?name="WCFService.WCFServiceSingleTon">
????????<endpoint
??????????address="net.tcp://localhost:9003/WCFServiceSingleTon"
??????????binding="netTcpBinding"
??????????contract="WCFService.IWCFService">
????????</endpoint>
????????<endpoint?address="mex"?binding="mexTcpBinding"?contract="IMetadataExchange"?/>
????????<host>
??????????<baseAddresses>
????????????<add?baseAddress="net.tcp://localhost:9003/"/>
??????????</baseAddresses>
????????</host>
??????</service>
????</services>
【4.3】客戶端:
? 運行宿主,添加服務引用,反序列化服務元數(shù)據(jù)為本地代碼。完成以后添加測試的代碼。每種服務激活類型創(chuàng)建2個代理實例,分別調(diào)用2次服務,測試不同的服務激活類型設置對服務實例的影響。我們來觀察服務實例化的次數(shù)。具體代碼如下:
////單調(diào)服務//????????????#region?//1.單調(diào)服務代理1?實例化,每次調(diào)用操作,會創(chuàng)建不同的服務實例
????????????WCFServicePerCall.WCFServicePerCallClient?WCFServicePerCallProxy1?=?new?WCFServicePerCall.WCFServicePerCallClient();
????????????//調(diào)用2次服務
????????????for?(int?i?=?0;?i?<?2;i++?)
????????????{
????????????????WCFServicePerCallProxy1.SayHello();
????????????}
????????????//關閉服務代理
????????????WCFServicePerCallProxy1.Close();
????????????WCFServicePerCall.WCFServicePerCallClient?WCFServicePerCallProxy2?=?new?WCFServicePerCall.WCFServicePerCallClient();
????????????//調(diào)用2次服務
????????????for?(int?i?=?0;?i?<?2;?i++)
????????????{
????????????????WCFServicePerCallProxy2.SayHello();
????????????}
????????????//關閉服務代理
????????????WCFServicePerCallProxy2.Close();
????????????#endregion
????????????////會話服務////
????????????#region//2.會話服務代理?實例化,一個客戶端代理對應一個服務實例
????????????WCFServicePerSession.WCFServicePerSessionClient?WCFServicePerSessionProxy1?=?new?WCFServicePerSession.WCFServicePerSessionClient();
????????????//調(diào)用2次服務
????????????for?(int?i?=?0;?i?<?2;?i++)
????????????{
????????????????WCFServicePerSessionProxy1.SayHello();
????????????}
????????????//關閉服務代理
????????????WCFServicePerSessionProxy1.Close();
????????????WCFServicePerSession.WCFServicePerSessionClient?WCFServicePerSessionProxy2?=?new?WCFServicePerSession.WCFServicePerSessionClient();
????????????//調(diào)用2次服務
????????????for?(int?i?=?0;?i?<?2;?i++)
????????????{
????????????????WCFServicePerSessionProxy2.SayHello();
????????????}
????????????//關閉服務代理
????????????WCFServicePerSessionProxy2.Close();
????????????#endregion
????????????////單例服務//
????????????#region//2.單例服務代理?實例化,也叫單件模式。所有的服務只有一個服務實例
????????????WCFServiceSingleTon.WCFServiceSingleTonClient?WCFServiceSingleTonProxy1?=?new?WCFServiceSingleTon.WCFServiceSingleTonClient();
????????????//調(diào)用2次服務
????????????for?(int?i?=?0;?i?<?2;?i++)
????????????{
????????????????WCFServiceSingleTonProxy1.SayHello();
????????????}
????????????WCFServiceSingleTonProxy1.Close();
????????????WCFServiceSingleTon.WCFServiceSingleTonClient?WCFServiceSingleTonProxy2?=?new?WCFServiceSingleTon.WCFServiceSingleTonClient();
????????????//調(diào)用2次服務
????????????for?(int?i?=?0;?i?<?2;?i++)
????????????{
????????????????WCFServiceSingleTonProxy2.SayHello();
????????????}
????????????WCFServiceSingleTonProxy2.Close();
????????????#endregion
????????????//4.For?Debugging
????????????Console.WriteLine("Press?any?key?to?continue");
????????????Console.Read();
【4.4】運行結果:
???? 啟動托管宿主,運行客戶端進行測試,監(jiān)控服務輸出信息如下:
【5】總結:
(1)單調(diào)服務每次都重新創(chuàng)建服務的實例,操作完成以后,釋放服務對象,每次想用用戶操作請求的服務實例不同。
(2)會話服務針對每次會話創(chuàng)建一個特定的服務實例對象,在一次會話中的所有請求由一個服務對象相應。我們的服務調(diào)用計數(shù)也在會話期間隨客戶端調(diào)用的次數(shù)增加,上圖可見。
(3)單例服務在宿主創(chuàng)建時就進行了實例化。他和會話和調(diào)用次數(shù)沒有關系,所有的客戶單服務調(diào)用操作均有同一個服務實例來響應。客戶單調(diào)用的次數(shù)越多,服務端實際調(diào)用次數(shù)就會隨之增加。上圖可見。
(4)另外我們也可以編程或者配置系統(tǒng)的最大并發(fā)調(diào)用數(shù)、最大并發(fā)會話數(shù)、最大并發(fā)實例數(shù),來控制和管理服務實例的負荷和流量。
http://blog.csdn.net/book_frank_xl/article/details/4735912轉(zhuǎn)載于:https://www.cnblogs.com/quietwalk/archive/2011/08/09/2132525.html
總結
以上是生活随笔為你收集整理的WCF服务实例激活类型编程与开发(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 4-7月份规划
- 下一篇: 修改FTP密码的三种方法