如果我们熟悉设计模式,可以以单例模式的方式思考单例服务。所谓单例服务,就是针对所有客户端而言,都只有一个服务实例。“单例服务的生存期是无限的,只有在关闭宿主时,才会被释放。创建宿主时,单例服务会被创建,并且只能被创建一次。”
可以通过InstanceContextMode.Single的InstanceContextMode属性配置单例服务:
只要是单例服务,即使该服务支持多个契约,这些契约中有的需要会话,有的不需要会话,在不同终结点的调用仍然是通过相同的实例进行传递。即使关闭了代理,也不会终止单例服务。[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] class MySingleton : ... {...}
在实例化单例服务对象时,可能需要执行一些初始化的工作。如果使用默认的构造函数,并通过ServiceHost托管服务,是没有办法做到这一点的。当然,我们也可以在默认构造函数中实现这些初始化的工作,然而如果初始化工作需要一些特别的定制步骤,特别是需要操作状态或者需要传入参数时,默认的构造函数就显得捉襟见肘了。
WCF提供了另外一种初始化单例服务的办法,就是利用ServiceHost类提供的专门的构造函数,可以接收一个object对象:
注意,构造函数中的singletonInstance必须是配置为单例方式的服务对象。因此,初始化以及托管单例服务的方式可以如下实现:public class ServiceHost : ServiceHostBase,... { public ServiceHost(object singletonInstance, params Uri[] baseAddresses); public virtual object SingletonInstance {get;} //More members }
很显然,ServiceHost提供的这个构造函数还有改进的余地,那就是object类型参数显然不具备类型安全,因而本书作者定义了新的ServiceHost类,引入了泛型://Service code [ServiceContract] interface IMyContract { [OperationContract] void MyMethod( ); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] class MySingleton : IMyContract { int m_Counter = 0; public int Counter { get { return m_Counter; } set { m_Counter = value; } } public void MyMethod( ) { m_Counter++; Trace.WriteLine("Counter = " + Counter); } } //Host code MySingleton singleton = new MySingleton( ); singleton.Counter = 42; ServiceHost host = new ServiceHost(singleton); host.Open( ); //Do some blocking calls then host.Close( ); //Client code MyContractClient proxy = new MyContractClient( ); proxy.MyMethod( ); proxy.Close( ); //Output: Counter = 43
单例服务与可伸缩性之间的关系可谓“水火不容”。因而除非是在特殊情况,应尽量避免使用单例服务。public class ServiceHost<T> : ServiceHost { public ServiceHost(T singleton,params Uri[] baseAddresses) : base(singleton,baseAddresses) {} public virtual T Singleton { get { if(SingletonInstance == null) { return default(T); } return (T)SingletonInstance; } } //More members }