从执行方式与激活方式来看,会话服务相当于.NET Remoting中的客户端激活模式。也就是为每个客户端创建一个专门的服务实例。只要会话没有结束,该实例就不会被销毁。
“客户端会话是一个代理对应一个服务终结点。如果客户端为相同或不同的终结点创建了另外的代理,则新建的代理就会与新的实例和会话建立关联。”根据这句话的内容,可以理解到对于会话服务而言,是一个客户端代理对应一个服务实例。也就是说,会话服务中的服务是与代理相对应的,而不是对应于一个客户端。这是它与.NET Remoting的客户端激活模式不同的地方。
此外,会话服务存在可伸缩性的问题。由于每个客户端都需要维护一个会话,如果存在多个独立的客户端,则创建专门的服务实例的代价太大。
配置会话服务的方式仍然是使用ServiceBehavior特性,如下所示:
然而,InstanceContextMode的默认值为InstanceContextMode.PerSession,如果没有设置InstanceContextMode,则服务默认为会话服务。[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] class MyService : IMyContract {...}
仅仅为服务配置InstanceContextMode是不够的,因为会话服务必须要求客户端维持一个会话,这就需要让客户端的WCF运行时知道服务是否使用了会话,因此,我们需要通过ServiceContract特性提供的SessionMode属性,设置服务契约。SessionMode的定义如下:
“SessionMode的默认值为SessionMode.Allowed。当客户端导入契约元数据时,服务元数据将包含SessionMode值,并会如实地反映它的内容。”public enum SessionMode { Allowed, Required, NotAllowed }
如果服务的SessionMode被配置为SessionMode.Allowed,并不必然代表服务为会话服务。以下是对各种情况的说明:
1、 如果服务被配置为单调服务,则服务与SessionMode无关;
2、 如果服务被配置为会话服务,且SessionMode为Allowed,则:
(1)如果服务使用的绑定为BasicHttpBinding,服务为单调服务;
(2)如果服务使用的绑定为没有包含安全与可靠消息传输的WSHttpBinding绑定,服务为单调服务;
(3)如果服务使用的WSHttpBinding绑定包含了安全(为默认配置)或者可靠的消息传输,或者使用NetTcpBinding绑定、NetNamedPipeBinding绑定,服务为会话服务。
当SessionMode为Required时,服务不能使用BasicHttpBinding绑定或者没有包含安全与可靠消息传输的WSHttpBinding绑定,在装载服务时会对此进行验证。作者建议,“若要设计一个会话契约,我主张使用SessionMode.Required,而非SessionMode.Allowed默认值。”
如果SessionMode为NotAllowed,则不管服务配置如何,它总是采用单调服务方式。但如果契约使用了NetTcpBinding或NetNamedPipeBinding绑定,则不能将服务的SessionMode配置为NotAllowed。作者的建议是“是在选择使用SessionMode.NotAllowed的同时,总是将服务配置为单调服务”。
应该避免将单调服务与会话契约混合定义在相同的会话服务类型中,即使WCF允许这样的配置:
[ServiceContract(SessionMode = SessionMode.Required)] interface IMyContract {...} [ServiceContract(SessionMode = SessionMode.NotAllowed)] interface IMyOtherContract {...} //Avoid class MyService : IMyContract,IMyOtherContract {...}
会话应该保证是可靠的,一个实现了会话契约的服务,它包含的所有终结点所公开的契约都应该使用支持可靠传输会话的绑定。
“通常,一旦客户端关闭了代理,会话就会终止。但是,客户端也可以强行终止会话,也可能因为通信故障而终止会话。每个会话还包含了一个空闲超时值,默认为10分钟。如果客户端在10分钟内没有任何操作,那么即使客户端期望继续使用该会话,会话仍然会自动终止。会话如果是因为空闲超时的原因被终止,那么当客户端试图使用它的代理时,会获得一个CommunicationObjectFaultedException异常。在绑定中通过配置不同的值,可以为客户端和服务配置不同的超时值。支持可靠传输层会话的绑定提供了ReliableSession属性,类型为ReliableSession或者OptionalReliableSession。ReliableSession类定义了InactivityTimeout属性,属于TimeSpan类型,通过它可以配置一个新的空闲超时值。”
注意,InactivityTimeout属性的默认值为10分钟。不能将该值设置为小于或等于0的值,否则会抛出ArgumentOutOfRangeException异常。
例如,下面的代码利用编程方式将TCP绑定的空闲超时值配置为25分钟:
NetTcpBinding tcpSessionBinding = new NetTcpBinding( ); tcpSessionBinding.ReliableSession.Enabled = true; tcpSessionBinding.ReliableSession.InactivityTimeout = TimeSpan.FromMinutes(25);
这等同于配置config文件:
<netTcpBinding> <binding name = "TCPSession"> <reliableSession enabled = "true" inactivityTimeout = "00:25:00"/> </binding> </netTcpBinding>
如果客户端与服务都配置了超时值,则以短的超时值为准。