WCF足迹3:实例

WCF服务端需要处理大量客户端的请求,每个客户端可能要与一个或多个服务实例进和交互,这种交互模式有很多种,这也就决定了服务器端对实例的管理不能搞“一刀切”,需要具有有效的实例的管理功能。
WCF服务支持三种实例管理模式:
per-call:针对客户端的每个请求创建一个新的服务实例。
sessionful:针对每个连接的客户端创建一个服务实例。
singleton:所有的客户端共享一个服务实例。


一、Per-Call服务:
在服务被配置成Per-Call实例模式的状态时,客户端代理每次对服务契约调用,WCF都会产生一个新服务实例来处理客户请求,当处理完请求后,WCF就会把服务实例作为一个垃圾,等待垃圾回收器来清理。
即使同一个客户端先后两次调用服务契约,WCF也会产生两个不同的服务实例来处理客户端请求。



《图0》
特点:
1.服务实例在方法被调用时创建,调用完立即释放
2.吞吐量大,内存开销少。能有效节约服务器内存,也不会过长时间占用昂贵的服务器资源(数据库连接,文件指针等)。
3.不会产生并发问题
4.两次调用之间不会保存状态

代码实现:
[ServiceContract]
public interface IPerCall
{
    [OperationContract]
    int Add();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class PerCall : IPerCall
{
    private int _Count = 0;
    public int Add()
    {
        _Count++;
        return _Count;
    }
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]特性只能应用到类上。
上面的代码中,是PerCall调用模式,每次调用PerCall类的Add()方法时,都会生成PerCall类的新对象,并把其_Count成员初始化为0,然后再调用Add()方法中的代码,把_Count成员变量自增1。所以每次调用Add()方法完成后,返回结果应当总是1。
使用“WCF测试客户端”我们可以运行Add()方法,点击“调用”发现每次返回的结果都是1。



《图1》

二、Sessionful服务:
当服务的实例模式指定为Sessionful时,每个客户端代理会取得一个独享的服务实例,并进行一对一的调用,这个服务实例不会在一次调用后立即释放,而会一直存在,直到客户端代理关闭(当客户端代理关闭时会通知服务会话结束)。这种模式有点像传统的C/S模式。
特点:
1.需要在服务器端管理实例状态
2.吞吐量下降
3.服务器资源开销过多
4.事务控制麻烦等问题。
5.一般来说,它只能为几十个客户端进行服务。

注:如果客户端启用另一个代理请求服务,那会在服务端产生一个新的独享服务实例来与之交互。

代码实现:
[DataContract]
public class CallingResult
{
    private string _SessionID;
    [DataMember]
    public string SessionID
    {
        get { return _SessionID; }
        set { _SessionID = value; }
    }
    private int _Value;
    [DataMember]
    public int Value
    {
        get { return _Value; }
        set { _Value = value; }
    }
}

[ServiceContract]
public interface IPerSession
{
    [OperationContract]
    CallingResult Add();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class PerSession : IPerSession
{
    private CallingResult _result;
    public PerSession()
    {
        _result = new CallingResult();
        _result.SessionID = OperationContext.Current.SessionId;
        _result.Value = 0;
    }
    public CallingResult Add()
    {
        _result.Value++;
        return _result;
    }
}
运行结果:



《图3》

上面的[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]声明指示PerSession服务的实例管理模式是PerSession模式,但并不是只要加上此声明就可以在服务器上保存实例状态。要在服务器上保留服务实例,并维持服务实例与客户端的一一对应关系,那需要WCF能够识别出不同的客户端,然后才能把特定客户端对应到特定的服务实例上去。并不是所有的绑定信道都能够识别出不同客户端的。
1.NetTcpBinding和NetNamedPipeBinding两种绑定能够在客户端和服务端保持一个持续的连接,所以它们可以很好地把客户端与服务实例关联起来。可以使用PerSession实例模式
2.BasicHttpBinding绑定是通过Http协议进行数据传输的一种简单的绑这下,而Http协议本身又是一种无状态协议,所以服务端无法区分每次请求的客户端。因此在这种绑定信道上是无法使用PerSession模式的。
3.WSHttpBinding绑定也是通过Http协议进行数据传输的,当然Http协议本身也是无状态的,但它可以在消息头中包含ID来识别不同的客户端。因此,当WSHttpBinding在安全模式和可信赖消息模式下是可以使用PerSession模式的

虽然上面所说的NetTcpBinding、NetNamedPipeBinding和WSHttpBinding三种绑定信道可以使用PerSession模式,但需要让客户端知道该契约是否需要保持状态,因此我们在定义服务契约的时候需要指明该契约的会话模式,这里就用到了ServiceContract契约的SessionMode属性:
public enum SessionMode
{
   Allowed,
   Required,
   NotAllowed
}
[AttributeUsage(AttributeTargets.Interface|AttributeTargets.Class,Inherited=false)]
public sealed class ServiceContractAttribute : Attribute
{
   public SessionMode SessionMode
   {get;set;}
   //More members
}
1.SessionMode.Allowed:这是SessionMode属性的默认值。启用传输会话,但应用程序不必须使用会话如果该服务行为声明为PerCall,那它仍不会保留实例状态。如果服务声明为PerSession,那它会根据信道情况确定是否保留实例状态。
    BasicHttpBinding和WSHttpBinding两种绑定并不支持传输会话,所以即使服务行为被配置为PerSession,那它依然采用PerCall的调用方式。
    NetTcpBinding、NetNamedPipeBinding和WSHttpBinding安全可信赖绑定支持传输会话,如果服务行为被配置为PerSession,那它采用PerSession调用方式。
   
2.SessionMode.Required:指定绑定信道必须支持传输会话如果绑定信道不支持传输会话,在加载服务的时候会产生异常。
    当服务行为指定为PerSession时,那此时服务端实例与客户端代理可以实现一对一的调用,并能保存服务端实例的状态。
    当服务行为指定为PerCall时,那此时仍不会在服务端保存实例状态。
    如果要设计带有会话状态的服务契约的时候,建议把服务契约的SessionMode设为SessionMode.Required。
   
3.SessionMode.NotAllowed:不启用传输会话禁止服务保存服实例的状态服务永远是PerCall模式

绑定、契约和服务行为的关系:
1.绑定指的是绑定信道:BasicHttpBinding、NetTcpBinding、NetNamedPipeBinding和WSHttpBinding等
2.契约指的是ServiceContract的SessionMode属性:SessionMode.Allowed、SessionMode.Required、SessionMode.NotAllowed
3.服务行为指的是ServiceBehavior的InstanceContextMode属性:InstanceContextMode.PerCall、InstanceContextMode.PerSession、InstanceContextMode.Singleton
这三者的关系在需要保持会话状态时(PerSession)关系很密切。而在PerCall和Singleton时并无太大关联。



《图4》
这里举个例子来说明这三个的关系:
随着城市的规模越来越大,公共交通问题会越来越严重,假设一个城市A想要快速公交系统,那这个城市A必须要具备三个基本条件:路要好、车要快和合理的交通规则。
车速:相当于是否启动程序会话。车速低相当于不启用程序会话,车速高相当于启用程序会话。
路:相当于绑定信道。地铁,轻轨这二者自然是快速路,而普通的马路则不行,一旦堵车就快不起来了,但如果在马路上划出公交专用通道,那公交的速度会大大加快,也可以作为快速公交看待。
车:相当于服务行为[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]。如果车太落后,行驰速度像马车,那即使有了好的路不见得车就一定能快起来。也就是说虽然绑定信道支持传输会话,但服务行为设为PerCall那仍然是单一调模式。
交通规则:相当于契约中的传输会话的声明[ServiceContract(SessionMode = SessionMode.Allow)]。如果有了好的路,有了好的车,但交通规则规定时速不得超过5公里,那照样快不起来。也就是说绑定绑定信道支持传输会话,服务行为也设为PerSession,但就是契约的SessionMode设为NotAllow,那照样无法实现应用程序会话。反过来说,如果路面太差不支持快速公交的条件(绑定不支持传输会话),车又很好跑得很快(InstanceContextMode.PerSession),交通规则还要求车行速度不低于200码(SessionMode=Required),那肯定会出异常

应用程序Session的维持时间默认为10分钟。可以在每个绑定上使用receiveTime指定Session时长。
<netTcpBinding>
   <binding name = "TCPSession">
      <reliableSession enabled = "true" inactivityTimeout = "00:00:05"/>
   </binding>
</netTcpBinding>



《图7》

三、Singleton服务
Singleton模式是终极服务共享模式,所以客户端共享一个服务实例,不管你是采用什么样的绑定信道。服务实例在宿主程序运行的时候创建,在宿主程序结束的时候释放,中间全程占用服务器资源。



《图5》
特点:
1.所有客户端调用同一实例
2.吞吐量受影响
3.对象在内存中占用时间较长
4.容易产生并发性问题

代码:
[DataContract]
public class CallingResult
{
    private string _SessionID;
    [DataMember]
    public string SessionID
    {
        get { return _SessionID; }
        set { _SessionID = value; }
    }
    private int _Value;
    [DataMember]
    public int Value
    {
        get { return _Value; }
        set { _Value = value; }
    }
}

[ServiceContract]
public interface IPerCall
{
    [OperationContract]
    CallingResult Add();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class PerCall : IPerCall
{
    private CallingResult _result;
    public PerCall()
    {
        _result = new CallingResult();
        _result.SessionID = Guid.NewGuid().ToString();
        _result.Value = 0;
    }
    public CallingResult Add()
    {
        _result.Value++;
        return _result;
    }
}

启运两个WCF测试客户端,运行效果如下:



《图6》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值