实例上下文
实例上下文是对服务实例的封装 是WCF管理服务实例生命周期的依托 一个WCF服务通过ServiceHost进行寄宿 开启服务后当接收到请求 则会判断当前是否存在实例上下文 如果存在 则通过它得到服务实例来处理请求 否则将创建服务实例并将其封装在实例上下文中 然后通过实例上下文调用具体的服务实例来处理请求
实例上下文模式
实例上下文模式可以简单的理解为服务端的服务实例与客户端的服务代理之间的关联方式 WCF具有如下三种实例上下文模式
实例上下文单调模式(Per-Call)
如果采用单调实例上下文模式 那么无论请求来自相同的客户端还是其它客户端 WCF总是为当前请求创建一个新的服务实例和新的实例上下文对象来处理请求 即每次请求都会导致服务实例和实例上下文的创建 一旦服务调用完成 服务端就会自动释放服务实例所占用的系统资源
实例上下文会话模式(Per-Seesion)
会话的目的在于保持来自相同客户端的请求与服务端之间的联系 在此模式下 WCF会为每个服务代理对象分配一个单独的服务实例上下文对象 对于来自相同客户端的请求都将分发给对应的实例上下文对象来处理 由于客户端服务代理在服务端始终保持着一个被它独占使用的实例上下文 要是代理对象一直不关闭 那么被实例上下文直接或间接引用的资源就会得不到及时的释放 将会带来资源的浪费 假设服务端能够同时维持10个实例上下文 这里我们假设来自不同客户端的总共10个请求都在调用完服务后不关闭代理 那么第11个请求到达时 它将无法做出处理 所以 实例上下文会话模式仅适用于客户端较少的应用 最主要的原因就在于 实例上下文维持客户端需要的资源 除非客户端显示的调用Dispose或Close关闭了代理 否则服务端无法释放资源
实例上下文单例模式(Single)
仅为每个服务维护唯一一个实例上下文对象 所以无论请求是来自哪个客户端 它们的代理对象调用的服务实例都只存在于一个实例上下文中 不同于其它两种模式是在请求时才创建建实例上下文和实例 在单例模式中实例上下文和实例都是在服务寄宿完成后被创建的 在默认情况下 服务实例上下文是以同步的方式工作的 即单例模式下 实例上下文在某个时刻只能处理某一个服务调用请求 而在并发请求中 只有一个请求能被有效处理 其它的请求则会被队列 如果请求在设定的超时时限过后还得不到处理 客户端就会抛出异常 单例模式的同步处理只能应付极少数量的客户端请求 可以将ServiceBehavior的并发模式属性ConcurrencyModel设为Multiple 以开启服务的异步处理 如果这样做 那么在单例模式下将采用异步方式 由多个线程使用同一个实例上下文处理请求 解决了队列请求的问题 在单例模式中 每个服务操作都是唯一的 既不会重新创建也不会自动释放 除非服务端关闭了进程导致服务寄宿的停止
ServiceBehavior特性的InstanceContextMode属性
我们可以通过ServiceBehavior的InstanceContextMode属性来配置服务要使用的是何种类型的实例上下文模式 该属性是一个枚举 提供的三个值分别对应了三种实例上下文模式
InstanceContextMode.PerCall:服务采用实例上下文单调模式
InstanceContextMode.PerSession:服务采用实例上下文会话模式
InstanceContextMode.Single:实例上下文单例模式
[ServiceContract(Namespace = "http://www.cnblogs.com/")]
public interface IBar
{
[OperationContract]
void Doth();
} [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class BarService : IBar
{
public void Doth() { }
}
ServiceContract特性的SessionModel属性
实例上下文模式通过ServiceBehavior的InstanceContextMode属性应用在服务上 而会话是基于双方的协议 所以可以将会话看成一个契约 即会话契约 会话契约用以声明契约是否支持会话通信 使用ServiceContract的SeesionModel属性来定义 该属性是一个枚举 提供了三个值来表示会话契约模式
SessionMode.Allowed:允许会话
SessionMode.NotAllowed:禁止会话
SessionMode.Required:强制会话
[ServiceContract(Namespace = "http://www.cnblogs.com/",SessionMode=SessionMode.Required)]
public interface IBar
{
[OperationContract]
void Doth();
}
OperationContract特性的IsInitiating和IsTerminating属性
此特性应用在契约操作上 使用这两个属性来控制会话的开启与关闭
IsInitiating:bool值 如果ServiceContract的SeesionModel允许或强制会话 指示当前操作是否开启会话 默认值true
IsTerminating:bool值 如果ServiceContract的SeesionModel允许或强制会话 指示当前操作是否关闭会话 默认值false
比如在如下两个契约操作上分别应用了IsInitiating和IsTerminating属性 服务代理调用Begin方法时会开启会话 调用end方法后则会关闭会话
[ServiceContract(Namespace = "http://www.cnblogs.com/")]
public interface IBaz
{
[OperationContract(IsInitiating=true)]
void begin();
[OperationContract(IsTerminating = true)]
void end();
}
注意 一旦关闭会话 则代理将无法再次调用服务操作
proxy.begin()
proxy.end()
proxy.begin()//再次调用服务操作则客户端将抛出异常
默认情况下 每个契约操作的IsInitiating属性都为true 即默认打开会话 即使绑定对象不支持会话 也不会抛出异常 如果ServiceContract的SeesionModel允许或强制会话且将x操作的IsInitiating设为false 则契约操作x不能被服务代理第一个调用 我们假设有三个契约操作如下代码所示 首先契约的SessionModel被设为强制会话 接着契约操作Begin开启会话 end操作结束会话 如果服务代理第一步调用服务时调用的是doth操作 则会抛出异常 因为该没有开启会话 而ServiceContract的SeesionMode被设为强制会话 操作中只有begin是开启会话的操作 所以它才是第一个应被调用的操作 接着才可以调用doth 最后调用end操作处理完请求后会自动关闭会话
[ServiceContract(Namespace = "http://www.cnblogs.com/",SessionMode=SessionMode.Required)]
public interface IBar
{
[OperationContract(IsInitiating=true,IsTerminating=false)]
void begin();
[OperationContract(IsInitiating=false,IsTerminating=false)]
void doth();
[OperationContract(IsInitiating = false, IsTerminating = true)]
void end();
}
会话绑定
会话的功能最终是由会话信道实现的 信道栈是由绑定对象创建的 并不是所有类型的绑定都能创建会话信道 所以纵然我们使用ServiceBehavior的InstanceContextMode属性将服务的实例上下文模式设为会话模式 使用ServiceContract的SeesionModel属性将契约定义为会话契约 但有些绑定本身就不支持会话 此时服务寄宿时就会抛出异常
BasicHttpBinding:不支持
WSHttpBinding | WS2007HttpBinding | WSDualHttpBinding:支持
但如果将该绑定对象的security(安全会话)设为none和reliableSession(可靠会话)设为false 则不支持会话 如
<system.serviceModel>
<bindings>
<ws2007HttpBinding>
<binding name="mybinding">
<security mode="None"/>
<reliableSession enabled="false"/>
</binding>
</ws2007HttpBinding>
</bindings>
</system.serviceModel>
</configuration>
NetTcpBinding | NetNamedPipeBinding | NetMsmqBinding:支持
提供了对会话的原生支持 即使将security设为none和reliableSession设为false也支持会话 使用该绑定时 契约接口的ServiceContract的SeesionModel必须设为强制或允许会话 不能是禁止