当发生一次WCF请求-响应操作时,会经过如下几个步骤
- WCF Client想WCF Server发送一个服务请求
- WCF Server创建WCF服务对象
- WCF Server调用WCF服务对象接口,将结果返回给WCF客户端。
操作过程中就牵涉到了服务对象的创建,但由于WCF服务对象是WCF框架管理,一般的时候并不关注它何时创建,何时回收。对于无需访问成员变量的状态无关的服务来说,这个并不影响我们的功能实现。
但是,许多时候我们也需要提供与状态相关的服务,这个时候需要通过服务对象的成员变量来保存状态。此时,我们就需要关注WCF的服务对象的创建策略了。下面就以一个计数器为例,介绍一下不同的策略对服务结果的影响。
[ServiceContract]
public interface IService1
{
[OperationContract]
int Increment();
}
[ServiceBehavior]
public class Service1 : IService1
{
private int intCounter;
public int Increment()
{
intCounter++;
return intCounter;
}
}
一般来讲,我们有如下三种策略创建WCF对象:
- PerCall 每次WCF服务调用都创建一个新的WCF服务对象,
- PerSession 每个WCF会话期间只创建一个WCF服务对象,如果没有会话设置,则效果同PerCall(默认策略)
- Single 所有WCF会话共享一个WCF服务对象
这三种策略可以ServiceBehavior在中通过InstanceContextMode显式设置。
ServiceBehavior(public class Service1 : IService1
注意:由于如果会话没有启用的话的话,PerSession效果同PerCall,而默认的协议basicHttpBinding不支持会话,为了正确演示这个示例,请将协议绑定到wsHttpBinding。
PerCall模式:
在这种方式下,每次WCF服务调用都创建一个新的WCF服务对象,调用完请求后,该对象便进入可回收状态。
在这种方式下,无论客户端如何调用,由于每次都是创建新对象,则计数永远都是1
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1 : IService1
{
}
PerSession模式
在这种模式下,每个会话对应一个服务对象,会话结束后服务对象被回收。也就是说:
- 同一个客户端的所有调用都发送给同一个服务对象
- 不同的客户端的调用发送给不同的服务对象
在这种方式下,每一个客户端都是独立计数的。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Service1 : IService1
{
}
Single模式
在这种模式下,所有会话都对应同一个服务对象。
这个方式下,所有的客户端的计数都会被累加起来。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service1 : IService1
{
}
服务对象生命周期和Dispose
虽然我们通过InstanceContextMode控制服务对象的生命周期,但是我们也无法得之服务对象何时释放。一般情况下,这个确实无需关心,但是,如果服务对象中如果在成员变量中保存了资源,我们就得需要确保资源能够及时释放。
按照.net设计原则,如果成员中保存了资源,则需要实现IDisposable接口,然后再Dispose方法中释放资源。实际上,在WCF中也是遵循这个规则的:对于实现了IDisposable接口的服务对象,在该对象生命周期结束后,就会调用其Dispose方法以确保及时释放资源。也就是说,只要我们的实现符合基础的设计准则,WCF框架自动及时释放。
活用一下这个规则:我们可以利用Dispose方法感知会话模式下成员的下线。
三种方式的比较
从性能上来看,Single模式全局只创建一个对象,开销最小。而PerCall每次调用都创建一个对象,看起来开销最大,但是它的可扩展性是最好的,非常容易实现负载分担,并且资源释放最为及时。
从功能上来看,PerSession和面向对象的模式最为接近,实现各种复杂的逻辑更为容易。