WCF实例上下文

实例上下文模式(IntanceContext Mode)表示服务端的服务实例与客户端的服务代理的绑定方式。

在WCF中有三种不同的实例上下文模式,单调(Per-Call)模式,会话(Per-Session),模式和单例(Single)模式.其中会话模式是默认的
 
单调模式:如果采用单调实例上下文模式,对于每一个服务调用,不论是来自相同的客户
端(服务代理)还是不同的客户端,WCF总是创建一个全新的服务实例和实例上下文
对象来处理服务调用请求。在服务操作执行完毕,实例上下文对象和被封装的服务实例
被回收掉.------------------------------------------------------------------------------只有这种模式资源可自动回收(要实现IDisposeable)
       
      
         对于实现了IDisposable接口的Dispose方法,有一点值得注意的是:该方法是以与操作
方法同步的形式执行的。也就是说,服务操作和Dispose方法在相同的线程中执行
认识这一点很重要,因为无论采用怎样的实例模式,在支持会话的情况下如果服务请求
来自于同一个服务代理,服务操作都会在一个线程下执行。对于单调模式就会出现这样
的问题:由于Dispose方法同步执行的特性,如果该方法是一个比较耗时的操作,那么来
自于同一个服务代理的服务后续调用请求将不能得到及时执行。WCF只能在上一个服务
实例被成功释放之后,才能处理来自相同服务代理的下一个服务调用请求.
                                                                              单调模式最大的优势:能够最大限度的发挥资源的利用,避免了资源的闲置及相互争用
 
会话模式:会话的目的在于保持来自相同客户端(即同一个服务代理)多次服务调用
之间的状态。如果从消息交互的角度来讲,通过会话可以将来自相同客户端的多个
消息关联在一起。在会话实例上下文模式下,WCF为每一个服务代理对象分配一个单独
的服务实例上下文对象,对于来自相同服务代理的所有服务调用请求,都将分发给相同
的服务实例上下文处理。
              
             现在,先后100个客户端(或者服务代理)进行服务调用请求,毫无疑问,100个服务实例
会被创建并同时存在于服务端的内存之中,并且每一个服务实例引用一个开启状态的数据
库连接,那么当来自第101个客户端服务调用请求抵达时,将得不到处理,除非在它的超
时时限到达之前,有一个客户端自动将服务代理关闭.
 但是,对于相同的场景,如果采用单调的模式,就能应付自如,因为每次服务调用之后
,数据库的连接可以及时地得到关闭和释放.
                                                                                
                                                                                 较之会话模式,单调模式能够处理更多的并发客户端。
 
 
 
单例模式下,WCF通过创建一个唯一的服务实例来处理所有的客户端服务调用请求。
这是一个极端的服务实例激活方式,由于服务实例的唯一性,所有客户端每次调用的
状态能够被保存下来,但是当前的状态是所有客户端作用于服务实例的结果,它不能
反映出具体某个客户端多次调用后的状态。WCF是一个典型的多线程的通信框架,对并
发的服务调用请求是最基本的能力和要求,但是服务实例的单一性就意味着相同服务实例
需要在多个线程下并发地调用.
                                                                                 并发多时这种模式其实不是很好,它会受并发模式影响。但是我们可以设多线程并发模式。如下可以达到单调一样的效果。
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single,ConcurrencyMode=ConcurrencyMode.Multiple)]
    public class Services:ICalculator
    {
        public double Add(double x, double y)
        {
            Thread.Sleep(5000);//单调不受它的影响,如是单例则要设多线程并发模式。如上
            return x + y;
        }
    }
   //在使用PerCall模式下,对于5个并发的服务调用均得到了及时的相应,这是我们希望看到
    //的结果.
   
    //在使用Single,情况就完全不一样了。从最终的结果可以看出,客户端得到执行
    //结果的间隔为5s.
    //WCF通过并发模式表示多线程访问单例服务对象的方式,而并发模式作为一种服务可以
    //通过ServiceBehaviorAttribute特性进行设定。WCF通过ConcurrencyMode枚举来表示
    //不同形式的并发模式,三个枚举值Single,Reentrant和Multiple分别表示单线程
    //重入,和多线程三种并发模式.


    //ConcurrencyMode.Single是默认采用的并发模式,这正是上面的例子中服务操作同步执行
    //的根本原因。为了让服务操作异步的执行,以提供服务的响应能力,我们只需要通过
    //ServiceBehaviorAttribute将并发模式设为ConcurrencyMode.Multiple就可以了.

 
     对于单例上下文模式,如果采用传统的基于服务类型的寄宿方式,即通过服务类型而
非服务实例创建ServiceHost对象,服务实例是通过WCF内部的服务实例激活机制创建的
。不同于其他两种实例上下文模式采用请求式实例激活方式(单调实例上下文在处理每次
调用请求时创建,而会话实例上下文模式则在接收到某个客户端的第一次调用请求时创建
服务实例上下文),单例实例上下文模式在ServiceHost的初始化过程中被创建。我们把
这种模式称为隐式单例模式.
 
 
  
会话模式定义在服务契约中,通过ServiceContractAttribute特性的SessionMode属性定义.
定义在SessionMode的3个枚举值分别对应3种不同的会话模式:Allowed,Reqired和NotAllowed.
Allowed:允许会话,对会话的具体支持依赖于绑定对会话的支持.            默 认
Required:强制服务契约提供对会话的支持,如果绑定不支持会话,抛出异常。 
NotAllowed:禁止会话.
默认使用的会话模式为SessionMode.Allowed,所以以下两种服务契约的定义方式是等效的.
[ServiceContract(Namespace=“http://www.ibeifeng.com/”,SessionMode=SessionMode.Allowed)]
Public interface ICalculator
{
}
[ServiceContract(Namespace=“http://www.ibeifeng.com/”)]
Public interface ICalculator
{
}
在进行基于会话服务调用中,会话开始于基于对应用服务代理的第一次服务调用,或者
通过Open方法人为开启服务代理.而当我们调用Close方法关闭服务代理的时候,也意味
着 会话结束.
 
会话模式的缺点:如果最大支持100个,但现在有101个进来,资源又没有被放(前台没有关)这时就会处于等待。
 
因此,会话实例上下文模式仅仅适合一些客户端数量很少的应用,并且在确定不使用服务
代理的时候,应该显示地将它们关闭
 
服务实例的释放。
可通过在服务的操作方法上应用OperationBehaviorAttribute特性设置相应的实例释放模式
,使实例在该操作方法执行之前或之后释放。实例释放模式通过System.ServiceMode.
ReleaseInstanceMode枚举表示.
ReleaseInstanceMode中的3个枚举值BeforeCall, AfterCall, BeforeAndAfterCall表示现有的服
务实例将在相应的操作执行之前,之后及前后被释放。默认值为
ReleaseInstanceMode.None,这 意味着不会执行基于该操作的实例释放操作在下面的
代码中,在Add方法中,通过OperationBehaviorAttribute特性将实例释放模式设置为
ReleaseInstanceMode.BeforeAndAfterCall,表明对于Add操作,WCF运行时每次都会为其
创建新的服务实例,并且该服务实例在完成该操作后会马上被释放.
 
 
 
 
小结:
 
1:尽可能使用PerCall服务.
2:对大规模的部署避免PerSession并发模式.
3:当需要PerSession服务时,尽量使用Single并发模式进行同步.
4:对于大规模服务器的部署,应避免Single并发模式.
5:总是检查代理状态,以确保服务器信道没有出现故障。
6:设置分流行为,使单一主机的进程每秒接受的请求约为300个,并确保调用者能得到新
的会话。
 
 
 
 

posted on 2013-12-03 21:00  peter.peng  阅读(1771)  评论(0编辑  收藏  举报