<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      我的WCF之旅(8):WCF中的Session和Instancing Management

      WCF中的Session

      我們知道,WCF是MS基于SOA建立的一套在分布式環境中各個相對獨立的Application進行Communication的構架。他實現了最新的基于WS-*規范。按照SOA的原則,相對獨自的業務邏輯以service的形式封裝,調用者通過Messaging的方式調用Service。對于承載著某個業務功能的實現的Service應該具有Context無關性、甚至是Solution無關性,也就是說個構成Service的operation不應該綁定到具體的調用上下文,對于任何調用,具有什么樣的輸入,就會有與之對應的輸出。因為SOA的一個最大的目標就是盡可能地實現重用,只有具有Context無關性/Solution無關性,Service才能實現最大限度的重用。此外Service的Context無關性/Solution無關性還促進了另一個重要的面向服務的特征的實現:可組合性,把若干相關細粒度的Service封裝成一個整體業務流程的Service。

      在一個C/S(Client/Service)場景中,Context無關性體現在Client對Service的每次調用都是完全不相關的。但是在有些情況下,我們卻希望系統為我們創建一個Session來保留某個Client和Service的進行交互的狀態。所以,像Web Service一樣,WCF也提供了對Session的支持。對于WCF來說,Client和Service之間的交互都通過Soap Message來實現的,每次交互的過程就是一次簡單的Message Exchange。所以從Messaging的角度來講,WCF的Session就是把某個把相關的Message Exchange納入同一個Conversation。每個Session用一個Session ID來唯一標識。

      WCF中的Session和ASP.NET的Session

      在WCF中,Session屬于Service Contract的范疇,是一個相對抽象的概念,并在Service Contract定義中通過SessionModel參數來實現。他具有以下幾個重要特征:

      • Session的創建和結束都有來自Client端的調用來實現

      我們知道,在WCF中Client通過創建的Proxy對象來和service的交互,在默認的支持Session的情況下,Session和具體的Proxy對象綁定在一起,當Client通過調用Proxy的某個方法來訪問Service的時候,Session被初始化,直到Proxy被關閉,Session被終止,我們可以通過下面兩種方式來關閉Proxy:

      1. 調用System.ServiceModel. ICommunicationObject對象(我們一般通過System.ServiceModel. ChannelFactory對象的CreateChannel方法獲得)的Close方法。
      2. 調用System.ServiceModel. ClientBase對象(我們一半通過繼承它來實現我們為某個特定的Service創建Proxy類)的Close方法。

      此外,我們也可以人為地指定通過調用Service的某個operation來初始化、或者終止Session。我們一般通過System.ServiceModel. OperationContractAttribute的IsInitiating和IsTerminating參數來指定初始化和終止Session的Operation。

      • WCF保證處于某個Session中傳遞的Message按照他發送的次序被接收
      • WCF并沒有為Session的支持而保存相關的狀態數據。

      說道WCF中的Session,我們很自然地聯想到ASP.NET中的Session。實際上,他們之間具有很大的差異:

      • ASP.NET的Session總是在Server端初始化的。
      • ASP.NET并不提供Ordered Message Delivery的擔保。
      • ASP.NET是通過在Serer以某種方式保存State來實現對Session的支持的,比如保存在Web Server的內存中,保存在State Server甚至是SQL Server中。

      WCF中的Session的實現和Instancing Management

      在上面我們說了,雖然WCF支持Session,但是并沒有相關的狀態信息被保存在某種介質中。WCF是通過怎樣的方式來支持Session的呢?這就是我們本節要講的Instancing Management。

      對于Client來說,它實際上不能和Service進行直接交互,它只能通過客戶端創建的Proxy來間接地實現和service的交互。Session的表現體現在以下兩種方式:

      • Session的周期和Proxy的周期綁定,這種方式體現為默認的Session支持。
      • Session的周期綁定到開始和終止Session的方法調用之間的時間內,這種方式體現在我們在定義Operation Contract時通過IsInitiating和IsTerminating顯式指定開始和終止Session的Operatoin。

      我們很清楚,真正的邏輯實現是通過調用真正的Service instance中。在一個分布式環境中,我們把通過Client的調用來創建最終的Service Instance的過程叫做Activation。在Remoting中我們有兩種Activation方式:Server Activation(Singleton和SingleCall),Client Activation。實際上對WCF也具有相似的Activation。不過WCF不僅僅創建對應的Service Instance,而且還構建相關的Context, 我們把這些統稱為Instance Context。不同的Activation方式在WCF中體現為的Instance context model。不同的Instance Context Mode體現為Proxy、Service 調用和Service Instance之間的對應關系。可以這么說,Instance Context Mode決定著不同的Session表現。在WCF中,支持以下3中不同級別的Instance Context Mode:

      • PerCall:WCF為每個Serivce調用創建 一個Service Instance,調用完成后回收該Instance。這種方式和Remoting中的SingleCall相似。
      • PerSession:在Session期間的所有Service調用綁定到某一個Service Instance,Session被終止后,Service Instance被回收。所以在Session結束后使用同一個Proxy進行調用,會拋出Exception。這種方式和Remoting中的CAO相似。
      • Singleton:這種方式和Remoting的Singelton相似。不過它的激活方式又有點特別。當為對應的Service type進行Host的時候,與之對應的Service Instance就被創建出來,此后所有的Service調用都被forward到該Instance。

      WCF的默認的Instance Context Mode為PerSession,但是對于是否對Session的支持,Instancing的機制有所不同。如果通過以下的方式定義ServiceContract使之不支持Session,或者使用不支持Session的Binding(順便說一下,Session的支持是通過建立Sessionful Channel來實現的,但是并不是所有的Binding都支持Session,比如BasicHttpBinding就不支持Session),WCF實際上會為每個Service調用創建一個Service Instance,這實質上就是PerCall的Instance Context Mode,但我為什么會說默認的是PerSession呢?我個人覺得我們可以這樣地來看看Session:Session按照本意就是Client和Service之間建立的一個持續的會話狀態,不過這個Session狀態的持續時間有長有短,可以和Client的生命周期一樣,也可以存在于某兩個特定的Operation調用之間,最短的則可以看成是每次Service的調用,所以按照我的觀點,PerCall也可以看成是一種特殊的Session(我知道會有很多人不認同我的這種看法。)

         [ServiceContract(SessionMode = SessionMode.NotAllowed)]

      Simple

      接下來我們來看看一個簡單的Sample,相信大家會對Session和Instancing Management會有一個深入的認識。這個Sample沿用我們Calculator的例子,Solution的結構如下,4個Project分別用于定義SeviceContract、Service Implementation、Hosting和Client。


      我們先采用默認的Session和Instance Context Modle,在這之前我們看看整個Solution各個部分的定義:

      1.    Service Contract:ICalculator

      using System;
      using System.Collections.Generic;
      using System.Text;
      using System.ServiceModel;

      namespace Artech.SessionfulCalculator.Contract
      {
          [ServiceContract]
          
      public interface ICalculator
          
      {
              [OperationContract(IsOneWay 
      = true)]
              
      void  Adds(double x);

              [OperationContract]
              
      double GetResult();
          }

      }

      2.    Service Implementation:CalculatorService

      using System;
      using System.Collections.Generic;
      using System.Text;
      using System.ServiceModel;
      using Artech.SessionfulCalculator.Contract;

      namespace Artech.SessionfulCalculator.Service
      {
          
      public class CalculatorService:ICalculator
          
      {

              
      private double _result;

              
      ICalculator Members

              
      public CalculatorService()
              
      {
                  Console.WriteLine(
      "Calculator object has been created");
              }


              
      ~CalculatorService()
              
      {
                  Console.WriteLine(
      "Calculator object has been destoried");
              }


          }

      }

      為了讓大家對Service Instance的創建和回收有一個很直觀的認識,我特意在Contructor和Finalizer中作了一些指示性的輸出。同時在每個Operation中輸出的當前的Session ID

      3.    Hosting

      Program

      using System;
      using System.Collections.Generic;
      using System.Text;
      using System.ServiceModel;
      using Artech.SessionfulCalculator.Service;
      using System.Threading;

      namespace Artech.SessionfulCalculator.Hosting
      {
          
      class Program
          
      {
              
      static void Main(string[] args)
              
      {
                  
      using(ServiceHost host = new ServiceHost(typeof(CalculatorService)))
                  
      {
                      host.Opened 
      += delegate
                      
      {
                          Console.WriteLine(
      "The Calculator service has begun to listen");
                      }
      ;
                      host.Open();
                      Timer timer 
      = new Timer(delegate { GC.Collect(); }null0100);
                      Console.Read();
                  }

              }

          }

      }

      除了Host CalculatorService之外,我還通過一個Timer對象每隔一個很短的時間(0.1s)作一次強制的垃圾回收,使我們通過輸出看出Service Instance是否被回收了。

      Configuration

      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
        
      <system.serviceModel>   
          
      <behaviors>
            
      <serviceBehaviors>
              
      <behavior name="CalculatorBehavior">
                
      <serviceMetadata httpGetEnabled="true" />
              
      </behavior>
            
      </serviceBehaviors>
          
      </behaviors>
          
      <services>
            
      <service behaviorConfiguration="CalculatorBehavior" name="Artech.SessionfulCalculator.Service.CalculatorService">
              
      <endpoint address="" binding="basicHttpBinding" bindingConfiguration=""
                contract
      ="Artech.SessionfulCalculator.Contract.ICalculator" />
              
      <host>
                
      <baseAddresses>
                  
      <add baseAddress="http://localhost:9999/SessionfulCalculator" />
                
      </baseAddresses>
              
      </host>
            
      </service>
          
      </services>
        
      </system.serviceModel>
      </configuration>

      我們使用的是basicHttpBinding

      4.    Client

      using System;
      using System.Collections.Generic;
      using System.Text;
      using System.ServiceModel;
      using Artech.SessionfulCalculator.Contract;

      namespace Artech.SessionfulCalculator.Client
      {
          
      class Program
          
      {
              
      static void Main(string[] args)
              
      {
                  ChannelFactory
      <ICalculator> calculatorChannelFactory = new ChannelFactory<ICalculator>("httpEndpoint");
                  Console.WriteLine(
      "Create a calculator proxy: proxy1");
                  ICalculator proxy1 
      = calculatorChannelFactory.CreateChannel();
                  Console.WriteLine(
      "Invocate  proxy1.Adds(1)");
                  proxy1.Adds(
      1);
                  Console.WriteLine(
      "Invocate  proxy1.Adds(2)");
                  proxy1.Adds(
      2);
                  Console.WriteLine(
      "The result return via proxy1.GetResult() is : {0}", proxy1.GetResult());

                  Console.WriteLine(
      "Create a calculator proxy: proxy2");
                  ICalculator proxy2
      = calculatorChannelFactory.CreateChannel();
                  Console.WriteLine(
      "Invocate  proxy2.Adds(1)");
                  proxy2.Adds(
      1);
                  Console.WriteLine(
      "Invocate  proxy2.Adds(2)");
                  proxy2.Adds(
      2);
                  Console.WriteLine(
      "The result return via proxy2.GetResult() is : {0}", proxy2.GetResult());

                  Console.Read();
              }

          }

      }

      我創建了兩個Proxy:Proxy1和Proxy2,并以同樣的方式調用它們的方法:Add->Add->GetResult。

      Configuration

      <?xml version="1.0" encoding="utf-8" ?>
      <configuration>
          
      <system.serviceModel>
              
      <client>
                  
      <endpoint address="http://localhost:9999/SessionfulCalculator"
                      binding
      ="basicHttpBinding" contract="Artech.SessionfulCalculator.Contract.ICalculator"
                      name
      ="httpEndpoint" />
              
      </client>
          
      </system.serviceModel>
      </configuration>

      我們來看看運行的結果:

      Client端:


      雖然我們我們兩次調用Add方法進行累加,但是最終的結果 依然是0。這好像和我們開始所說的WCF默認的Session支持不相符,默認的Session支持是這樣:Service Instance和Proxy綁定在一起,當調用Proxy的任何一個方法的時候Session開始,從此Session將會和Proxy具有一樣的生命周期。但是這樣的一個前提的,我們需要通過支持Session的Binding來創建我們的Sessionful Channel。顯然basicHttpBinding是不支持Session的,所以WCF會采用PerCall的方式創建Service Instance。同時由于不支持Session的Binding,Session ID為null。所以我們會很容易想到,我們進行的每次Service的調用都會在Service端創建一個不同Instance,Host的輸出證明了這一點。


      既然我們說上面的執行結構是由于不支持Session的basicHttpBinding造成的,那么我們現在來使用一個支持Session的Binding:wsHttpBinding。我們只需改變Hosting的Endpoint的配置:

      <endpoint address="" binding="wsHttpBinding" bindingConfiguration=""
                contract
      ="Artech.SessionfulCalculator.Contract.ICalculator" />

      和Client的Endpoint的配置:

      <endpoint address="http://localhost:9999/SessionfulCalculator"
                      binding
      ="wsHttpBinding" contract="Artech.SessionfulCalculator.Contract.ICalculator"
                      name
      ="httpEndpoint" />

      現在再來看看執行的結果,首先看看Client:


      從兩個Proxy的最后 結果返回3,可以看出我們默認的Session起作用了。而且我們會容易想到,此時Server端會有兩個Service Instance被創建。進一步地,由于Client的Proxy還依然存在,Service Instance也不會被回收掉,我們通過Host的輸出來驗證這一點:


      從輸出可以看出,Constructor來兩次調用,這說明了兩個Service Instance被創建,基于同一個Service Instance的調用具有相同的Session ID。沒有Finalizer相應的輸出,說明Service Instance依然存在。除非你在Client端Close掉Proxy。

      我現在就來通過修改Client端的來Close掉Proxy:通過ICommunicationObject.Close來顯式地close掉Proxy

      static void Main(string[] args)
              
      {
                  ChannelFactory
      <ICalculator> calculatorChannelFactory = new ChannelFactory<ICalculator>("httpEndpoint");
                  Console.WriteLine(
      "Create a calculator proxy: proxy1");
                  ICalculator proxy1 
      = calculatorChannelFactory.CreateChannel();
                  Console.WriteLine(
      "Invocate  proxy1.Adds(1)");
                  proxy1.Adds(
      1);
                  Console.WriteLine(
      "Invocate  proxy1.Adds(2)");
                  proxy1.Adds(
      2);
                  Console.WriteLine(
      "The result return via proxy1.GetResult() is : {0}", proxy1.GetResult());
                  (proxy1 
      as ICommunicationObject).Close();

                  Console.WriteLine(
      "Create a calculator proxy: proxy2");
                  ICalculator proxy2
      = calculatorChannelFactory.CreateChannel();
                  Console.WriteLine(
      "Invocate  proxy2.Adds(1)");
                  proxy2.Adds(
      1);
                  Console.WriteLine(
      "Invocate  proxy2.Adds(2)");
                  proxy2.Adds(
      2);
                  Console.WriteLine(
      "The result return via proxy2.GetResult() is : {0}", proxy2.GetResult());
                  (proxy1 
      as ICommunicationObject).Close();

                  Console.Read();
              }

      那么我們現在看運行后Host的輸出,就會發現Finalizer被調用了:


      上面演示了默認的Session和Instancing Management,我們現在來顯式地制定Session Model,我們先修改ServiceContract使之不支持Session:

      [ServiceContract(SessionMode = SessionMode.NotAllowed)]
          
      public interface ICalculator
          
      {
              [OperationContract(IsOneWay 
      = true)]
              
      void  Adds(double x);

              [OperationContract]
              
      double GetResult();
          }

      看看Client的輸出:


      從最后的結果為0可以知道Session確實沒有起作用。我們說用Client基于Session的表現,其根本是Server端的Instancing。從上面可以看出,Server實際上是采用PerCall的Instance Context Model。我們可以從Hosting的輸出得到驗證:


      上面對不支持Session作了實驗,我們現在來顯式地允許Session,并制定開始和終止Session的Operation:

      using System;
      using System.Collections.Generic;
      using System.Text;
      using System.ServiceModel;

      namespace Artech.SessionfulCalculator.Contract
      {
          [ServiceContract(SessionMode 
      = SessionMode.Required)]
          
      public interface ICalculator
          
      {
              [OperationContract(IsOneWay 
      = true, IsInitiating = true, IsTerminating = false)]
              
      void  Adds(double x);

              [OperationContract(IsInitiating 
      = false,IsTerminating =true)]
              
      double GetResult();
          }

      }

      為了模擬當Session終止后繼續調用Proxy的場景,我進一步修改了Client的代碼:

      class Program
          
      {
              
      static void Main(string[] args)
              
      {
                  ChannelFactory
      <ICalculator> calculatorChannelFactory = new ChannelFactory<ICalculator>("httpEndpoint");
                  Console.WriteLine(
      "Create a calculator proxy: proxy1");
                  ICalculator proxy1 
      = calculatorChannelFactory.CreateChannel();
                  Console.WriteLine(
      "Invocate  proxy1.Adds(1)");
                  proxy1.Adds(
      1);
                  Console.WriteLine(
      "Invocate  proxy1.Adds(2)");
                  proxy1.Adds(
      2);
                  Console.WriteLine(
      "The result return via proxy1.GetResult() is : {0}", proxy1.GetResult());
                  Console.WriteLine(
      "Invocate  proxy1.Adds(1)");
                  
      try
                  
      {
                      proxy1.Adds(
      1);
                  }

                  
      catch (Exception ex)
                  
      {
                      Console.WriteLine(
      "It is fail to invocate the Add after terminating session because \"{0}\"", ex.Message);
                  }



                  Console.WriteLine(
      "Create a calculator proxy: proxy2");
                  ICalculator proxy2
      = calculatorChannelFactory.CreateChannel();
                  Console.WriteLine(
      "Invocate  proxy2.Adds(1)");
                  proxy2.Adds(
      1);
                  Console.WriteLine(
      "Invocate  proxy2.Adds(2)");
                  proxy2.Adds(
      2);
                  Console.WriteLine(
      "The result return via proxy2.GetResult() is : {0}", proxy2.GetResult());
                  

                  Console.Read();
              }

      現在看看 Client的輸出結果:


      我們發現當我們調用GetResult之后再次調用Add方法,Exception被拋出。原因很簡單,因為我們把GetResult方法標識為終止Session的Operation。所以當該方法被調用之后,Session被終止,對應的Service Instance也標識為可回收對象,此時再次調用,顯然不能保證有一個對應的Service Instance來Handle這個調用,顯然這是不允許的。

      以上我們對采用默認的Instance Context Model,不同的Session Model。現在我們反過來,在Session支持的前提下,采用不同Instance Context Model,看看結果又如何:

      我們把Client端的代碼回到最初的狀態:

      static void Main(string[] args)
              
      {
                  ChannelFactory
      <ICalculator> calculatorChannelFactory = new ChannelFactory<ICalculator>("httpEndpoint");
                  Console.WriteLine(
      "Create a calculator proxy: proxy1");
                  ICalculator proxy1 
      = calculatorChannelFactory.CreateChannel();
                  Console.WriteLine(
      "Invocate  proxy1.Adds(1)");
                  proxy1.Adds(
      1);
                  Console.WriteLine(
      "Invocate  proxy1.Adds(2)");
                  proxy1.Adds(
      2);
                  Console.WriteLine(
      "The result return via proxy1.GetResult() is : {0}", proxy1.GetResult());

                  Console.WriteLine(
      "Create a calculator proxy: proxy2");
                  ICalculator proxy2
      = calculatorChannelFactory.CreateChannel();
                  Console.WriteLine(
      "Invocate  proxy2.Adds(1)");
                  proxy2.Adds(
      1);
                  Console.WriteLine(
      "Invocate  proxy2.Adds(2)");
                  proxy2.Adds(
      2);
                  Console.WriteLine(
      "The result return via proxy2.GetResult() is : {0}", proxy2.GetResult());

                  Console.Read();
              }

      通過在Calculator Service上面運用ServiceBehavior,并指定InstanceContextMode為PerCall:

      [ServiceBehavior(InstanceContextMode =  InstanceContextMode.PerCall)]
          
      public class CalculatorService:ICalculator
      {
        
      }

      雖然我們ServiceContract被顯式指定為支持Session,看看運行的結果是否如此:


      看來并非如此,所以我們說client端表現出的Session實際上是對應的Instancing來實現的,現在采用PerCall的Instance Context Mode, Proxy的狀態是不可能被保留的。如果現在我們把Instance Context Mode設為PerSession,運行結果將會如我們所愿,現在我就不再演示了。

      我們來看看Single的Instance Context Mode:

      ServiceBehavior(InstanceContextMode =  InstanceContextMode.Single)]
      public class CalculatorService:ICalculator
      {
        
      }

      我們這次先來看Hosting的輸出結果,這是在剛剛啟動Hosting,Client尚未啟動時的Screenshot。


      在這之前我們都是Client通過Proxy調用相應的Service之后,Service Instance才開始創建,但是對于InstanceContextMode.Single,Service Instance卻早在Service Type被Host的時候就已經被創建了。

      現在啟動Client:


      同原來不一樣的是,第二個Proxy返回的結果是6而不是3,這是因為只有一個Service Instance,所有調用的狀態都將保留。從Hosting的輸出也可以驗證這一點:


      WCF相關內容:
      [原創]我的WCF之旅(1):創建一個簡單的WCF程序
      [原創]我的WCF之旅(2):Endpoint Overview
      [原創]我的WCF之旅(3):在WCF中實現雙向通信(Bi-directional Communication)
      [原創]我的WCF之旅(4):WCF中的序列化(Serialization)- Part I
      [原創]我的WCF之旅(4):WCF中的序列化(Serialization)- Part II
      [原創]我的WCF之旅(5):Service Contract中的重載(Overloading)
      [原創]我的WCF之旅(6):在Winform Application中調用Duplex Service出現TimeoutException的原因和解決方案
      [原創]我的WCF之旅(7):面向服務架構(SOA)和面向對象編程(OOP)的結合——如何實現Service Contract的繼承
      [原創]我的WCF之旅(8):WCF中的Session和Instancing Management
      [原創]我的WCF之旅(9):如何在WCF中使用tcpTrace來進行Soap Trace
      [原創]我的WCF之旅(10): 如何在WCF進行Exception Handling
      [原創]我的WCF之旅(11):再談WCF的雙向通訊-基于Http的雙向通訊 V.S. 基于TCP的雙向通訊

      [原創]我的WCF之旅(12):使用MSMQ進行Reliable Messaging
      [原創]我的WCF之旅(13):創建基于MSMQ的Responsive Service

      posted @ 2007-06-13 01:59  Artech  閱讀(34822)  評論(87)    收藏  舉報
      主站蜘蛛池模板: 国产成人AV性色在线影院| 国产精品久久无中文字幕| 91精品久久久久久无码人妻| 日韩精品一区二区三区日韩| 午夜无码国产18禁| 欧美奶涨边摸边做爰视频| 精品免费国产一区二区三区四区介绍| 人妻教师痴汉电车波多野结衣| 国精一二二产品无人区免费应用| 色偷偷亚洲女人天堂观看| 黄浦区| 国产乱码日韩精品一区二区| 欧洲中文字幕国产精品| 久久精品国产99麻豆蜜月| 十八禁午夜福利免费网站| 中文字幕人妻日韩精品| 欧美 亚洲 另类 丝袜 自拍 动漫 久久久久久久久毛片精品 | 国产在线中文字幕精品| 亚洲无av码一区二区三区| 漂亮人妻中文字幕丝袜| 欧美性猛交xxxx免费看| 色777狠狠狠综合| 成人国产精品中文字幕| 99热精品久久只有精品| 国产亚洲精品第一综合| 中文字幕日韩人妻一区| 国产女人在线视频| 久久综合色天天久久综合图片| 时尚| 好吊妞| 欧美日产国产精品日产| 久久国产成人高清精品亚洲| 亚洲国产欧美不卡在线观看| 在线播放国产精品一品道| 麻豆国产AV剧情偷闻女邻居内裤| 亚洲国产精品人人做人人爱| 九九热免费精品在线视频| 亚洲Av综合日韩精品久久久| 亚洲精品国产综合麻豆久久99 | 精品无人区卡一卡二卡三乱码| 久久国产乱子伦免费精品无码 |