转载

实例上下文模式:单例模式

单例模式效果可以用下面这张图表示,服务端的服务实例只有一个,任何一个客户端访问的服务端都是相同的服务实例。意味着服务端可以留下不同客户端的脚印。

实例上下文模式:单例模式

使用也很简单,只需要将ServiceBehavior的上下文模式InstanceContextMode设置为Single即可。可以参照上一篇介绍 实例上下文模式:单调模式

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]     public class Calculator : ICalculator,IDisposable     {        ......     }

上篇介绍实例上下文模式时有些概念没有讲清楚。这里来补一下。

ServiceHost有两个有参数的构造函数,分别是

public ServiceHost(object singletonInstance, params Uri[] baseAddresses);  public ServiceHost(Type serviceType, params Uri[] baseAddresses);

第一个构造函数,singletonInstance是指服务实例,即new Calculator()创建的实例对象。

第二个构造函数是指服务实例的类型,即typeof(Calculator)获得。

baseAddresses均指终结点的基地址,这里需要注意,每一种Binding类型只能有一个基地址。例如下面寄宿代码将会报错,因为baseAddrs中含有两个http的基地址。

实例上下文模式:单例模式

回到正题,通过观察ServiceHost的构造函数代码。会将服务实例放入singletoninstance,类型放入serviceType。  这两个字段在ServiceHost中都是私有的。Servciehost启动的时候先检查singletonInstance是否存在,若不存在则根据serviceType反射创建一个服务实例。

实例上下文模式:单例模式

了解单例的机制需要知道一下几点:

1.当服务启动时候会调用服务行为(ServiceBehavior)初始化ServiceHost。而服务行为实现了IServiceBehavior接口,它定义了一个ApplyDispatchBehavior接口。

public interface IServiceBehavior { void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters); void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase); void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase); }

此接口的作用是将创建的实例上下文(InstanceContext)附加到终点分发器(EndpointDispatcher)的DispatchRuntime的SingletonInstance上。

2.实例上下文提供者实现了接口IInstanceContextProvider,实例上下文提供者附加在终点分发器(EndpointDispatcher)的DispatchRuntime的InstanceContextProvider上。

public interface IInstanceContextProvider { InstanceContext GetExistingInstanceContext(Message message, IContextChannel channel); void InitializeInstanceContext(InstanceContext instanceContext, Message message, IContextChannel channel); bool IsIdle(InstanceContext instanceContext); void NotifyIdle(InstanceContextIdleCallback callback, InstanceContext instanceContext); }

当服务端接受到一个请求消息时,首先会调用GetExistingInstanceContext获取InstanceContext,再从上下文中获取服务实例,调用实例的方法。流程处理完毕后调用IsIdle方法,如果返回为true则标识当前实例上下文生命周期结束,GC回收。

上一篇介绍单调时,直接将GetExistingInstanceContext返回null,WCF会创建一个新的实例上下文,使用完毕后再调用Isdle,直接返回true,则让GC回收。因此就有了单调模型。

实例模型只需要保证在GetExistingInstanceContext时返回一个相同的实例上下文,并且不能被GC回收,因此IsIdle返回false即可。而这个相同的实例上下文,需要到终结点分发器中取出来。

下面自定义一个SingleServiceProvider,如前面所述,IsIdle返回false,确保不让GC回收。GetExistingInstanceContext返回内部的runtime中的SingletonInstanceContext。而这个runtime是在构造函数中指定。

public class SingleServiceProvider : IInstanceContextProvider {  private DispatchRuntime runtime;  public SingleServiceProvider(DispatchRuntime runtime)  {   this.runtime = runtime;  }  public InstanceContext GetExistingInstanceContext(Message message, IContextChannel channel)  {   return runtime.SingletonInstanceContext;  }  public void InitializeInstanceContext(InstanceContext instanceContext, Message message, IContextChannel channel)  {}  public bool IsIdle(InstanceContext instanceContext)  {   return false;  }  public void NotifyIdle(InstanceContextIdleCallback callback, InstanceContext instanceContext)  {} } 

自定义SingleAttribute,遍历终结点分发器,若终ServiceHost中的服务实例SingletonInstance存在,则直接获取用来构造InstanceContext;若不存在则用serviceType反射形式创建一个服务实例,再构造InstanceContext。

public class SingleAttribute : Attribute, IServiceBehavior {  public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)  {}  public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)  {   foreach (ChannelDispatcher channel in serviceHostBase.ChannelDispatchers)   {    foreach (EndpointDispatcher endpoint in channel.Endpoints)    {     DispatchRuntime runtime = endpoint.DispatchRuntime;     ServiceHost host = (ServiceHost)serviceHostBase;     object Instance = null;     if (null != host.SingletonInstance)     {      runtime.SingletonInstanceContext = new InstanceContext(serviceHostBase, host.SingletonInstance);      Instance = host.SingletonInstance;     }     else     {      Instance = Activator.CreateInstance(serviceDescription.ServiceType);      runtime.SingletonInstanceContext = new InstanceContext(serviceHostBase, Instance);     }     endpoint.DispatchRuntime.InstanceContextProvider = new SingleServiceProvider(runtime);     if (serviceDescription.ServiceType.GetInterfaces().Contains(typeof(IDisposable)))     {      FieldInfo field = typeof(ServiceHost).GetField("disposableInstance", BindingFlags.Instance | BindingFlags.NonPublic);      field.SetValue(host, Instance);     }    }   }  }  public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)  {} } 

当ServiceHost结束时会调用onClosed方法,里面会释放private的disposableInstance字段。所以这里也将创建的服务实例通过反射放到这里,这样ServiceHost关闭时也能让服务实例也能回收。

实例上下文模式:单例模式

实例上下文模式:单例模式

最后使用自定义的SingleAttribute,可以看到同样实现了单例效果,并没有针对每次调用都创建一个实例上下文。

[Single]     public class Calculator : ICalculator,IDisposable     {         ......     }

实例上下文模式:单例模式

正文到此结束
Loading...