大家都知道WCF会话模式有几个要求:1、会话契约;2、绑定支持;3、实例模式为PerSession。这几个要素是WCF支持的必要条件。

  • 会话契约:由服务端提供实现,客户端调用时只持有契约定义,所以需要通过契约定义告知客户端,服务端是支持会话的。
  • 绑定:会话没有绑定的支持也就无从谈起了。
  • InstanceContextMode为PerSession。通过它可以保证在会话期间,服务实例不会被销毁。

较为复杂的问题在于ServiceContract中SessionMode的设置。SessionMode定义如下:

// 摘要:
    //     指定可用于指示支持协定需要或支持的可靠会话的值。
    public enum SessionMode
    {
        // 摘要:
        //     指定当传入绑定支持会话时,协定也支持会话。
        Allowed = 0,
        //
        // 摘要:
        //     指定协定需要会话绑定。如果绑定并未配置为支持会话,则将引发异常。
        Required = 1,
        //
        // 摘要:
        //     指定协定永不支持启动会话的绑定。
        NotAllowed = 2,
    }

通过以上SessionMode的枚举定义可知:Required肯定是强制启用会话;NotAllowed强制不之处会话;Allowed允许启用会话。最麻烦的要数Allowed。首先Allowed是他是支持会话的,其次:它允许并不意味着客户端与服务端的信息交互一定是会话模式的。那么在什么情况下我们将契约定义为允许会话,服务端与客户端之间的通讯是会话模式?什么情况下又是非会话模式呢?会话模式与可靠会话之间有没有什么关系?在启用会话模式时,客户端的SessionId与服务端的SessionId一定是完全匹配的吗?带着这些问题,来进行一些说明。

1、绑定

先从绑定说起:basicHttpBinding它不能在信息头中嵌入SessionId,客户端与服务端之间基于Http的通讯也就不可能维持会话了;Msmq模式下,服务端与客户端可以是基于离线模式的,因此也不支持会话。对于Tcp类型的绑定,如NetTcpBinding与NetNamedPipeBinding由于使用的是带连接的Tcp作为传输协议,所以它是能支持会话的。

2、SessionMode下的SessionId

可以通过OperationContext的SessionId属性来访问SessionId。

服务端访问SessionId:

OperationContext.Current.SessionId

在客户端,需要先初始化OperationContextScope,后才能访问SessionId。如下:

       IContextChannel contextChannel = proxy as IContextChannel;      
               using (OperationContextScope contextScope = new OperationContextScope(contextChannel))
               {                  
                   string sessionId=OperationContext.Current.SessionId);
               }

3、SessionMode=SessionMode.Allowed下服务端与客户端的SessionId匹配程度

讨论之前,先给出契约以及服务实现。如下:

[ServiceContract(SessionMode = SessionMode.Allowed)]
    public interface IAdd
    {
        [OperationContract]        
        int Add(int x,int y);
    }
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class AddService : IAdd,IDisposable
    {

#region IAdd Members

public int Add(int x, int y)
        {
            if (null != OperationContext.Current.SessionId)
            {
                Console.WriteLine("SessionId is {0}", OperationContext.Current.SessionId);
            }
            else
            {
                Console.WriteLine("SessionId is null");
            }            
            return x + y;
        }

#endregion

public void Dispose()
        {
            Console.WriteLine("Dispose Thread Id is {0}",System.Threading.Thread.CurrentThread.ManagedThreadId);
        }
    }

3.1、NetTcpBinding的会话

3.1.1、启用可靠会话

在配置文件中进行配置即可。如下:

调用之后访问SessionId:

    using (ChannelFactory<IAdd> channelFactory = new ChannelFactory<IAdd>("tcp"))
            {
                IAdd proxy = channelFactory.CreateChannel();
                Console.WriteLine("result is {0}", proxy.Add(1, 2));
                IContextChannel contextChannel = proxy as IContextChannel;
                using (OperationContextScope contextScope = new OperationContextScope(contextChannel))
                {
                    Console.WriteLine("operationContextScope hashcode is {0}", contextScope.GetHashCode());
                    if (null == OperationContext.Current.SessionId)
                    {
                        Console.WriteLine("SessionId is null");
                    }
                    else
                    {
                        Console.WriteLine("Session is {0}", OperationContext.Current.SessionId);
                    }
                }
                
            }

服务端输出:

客户端输出:

在客户端调用之前获取SessionId:

服务端输出如下:

客户端输出如下:

如果在调用服务之前,手动打开代理,情况怎样呢?

将客户端的代码做如下修改:

IAdd proxy = channelFactory.CreateChannel();
               (proxy as ICommunicationObject).Open();
                IContextChannel contextChannel = proxy as IContextChannel;
                using (OperationContextScope contextScope = new OperationContextScope(contextChannel))
                {
                    Console.WriteLine("operationContextScope hashcode is {0}", contextScope.GetHashCode());
                    if (null == OperationContext.Current.SessionId)
                    {
                        Console.WriteLine("SessionId is null");
                    }
                    else
                    {
                        Console.WriteLine("Session is {0}", OperationContext.Current.SessionId);
                    }
                }
                Console.WriteLine("result is {0}", proxy.Add(1, 2));

服务端输出:

客户端输出:

3.1.2 禁用可靠会话(NetTcpBinding默认)

服务端输出:

客户端输出:

小结:在NetTcpBinding绑定下,如果启用可靠会话传输,则服务端与客户端的SessionId是相同的。如果禁用可靠会话,则两者SessionId是不一样的。另外,在进行第一次调用前,客户端获取不到SessionId。除非在调用之前手动打开代理。

3.2、ws*绑定

在ws-*绑定中,WCF通过在消息头中加入SessionId,通过SessionId来识别客户端(准确来说是代理)。以下使用WsHttpBinding进行说明。

3.2.1、禁用可靠会话(调用之前手动打开代理)

服务端输出:

客户端输出:

3.2.2、启用可靠会话

服务端输出:

客户端输出:

3.2.3、禁用会话(不手工打开代理,调用之前获取SessionId)

服务端输出:

小结:可靠会话对客户端SessionId有影响。在开启可靠会话时,如客户端在调用之前手动打开代理,则客户端与服务端的SessionId相同;如果调用之前不手动打开代理,则客户端获取不到SessionId,只有在第一次调用后才能获取到SessionId;在禁用可靠会话时,客户端在不手动打开代理的情况下调用服务会发生异常。

另外说明:使用Tcp作为传输协议,通过三次握手,它通过超时、丢包重传的机制保证客户端到服务端的消息传输成功,但与WCF中消息的可靠会话是有本质区别的。WCF中通过自身机制保证从RM源到目标源消息的发送以及确认机制、以及服务端中消息从目标源到最终交付对象之间消息的交付机制。使用NetTcpBinding时,我们可以通过它的默认构造函数看看构成的绑定元素有哪些。如下代码:

    var binding = new NetTcpBinding();
            BindingElementCollection collection = binding.CreateBindingElements();
            foreach (BindingElement bindingElement in collection)
            {
                Console.WriteLine(bindingElement.GetType());
            }
            Console.WriteLine("--------使用构造函数,设置NetTcpBinding允许可靠会话--------");
            var binding2 = new NetTcpBinding(SecurityMode.None,true);
            BindingElementCollection collection2 = binding2.CreateBindingElements();
            foreach (BindingElement bindingElement in collection2)
            {
                Console.WriteLine(bindingElement.GetType());
            }

输出如下:

上图中ReliableSessionBindingElement就是创建可开会话信道的。

总结:不同类型的协议对于SessionId的获取是有影响的。无论对于TCP协议还是ws-* 协议,如果客户端调用之前不手动打开代理,则调用之前客户端是获取不到SessionId的;在进行第一次调用之后,客户端才能获取到与服务端相同的SessionId(因为进行调用时,会自动打开代理).
是否启用会话也会影响到SessionId。对于TCP协议来说,禁用可靠会话,客户端获取到SessionId与服务端是不一样的;对于ws-* 协议而言:如果禁用可靠会话,调用之前如果不手动代开代理,则调用会发生异常。

转载于:https://www.cnblogs.com/tyb1222/archive/2012/10/15/2724323.html

细说WCF中的会话模式相关推荐

  1. 在Windows Server 2012 R2的Hyper-V中设置虚拟机启用增强会话模式

    在Windows Server 2012 R2的Hyper-V中,可以为虚拟机提供一种全新的连接方式,就是"增强会话模式",它将让您更加方便的对虚拟机进行操作,比如分辨率的调整.设 ...

  2. WCF中的管道——管道类型

    管道是所有消息进出WCF应用程序的渠道.它的职责是以统一的方式编制和提供消息.管道中定义了传输.协议和消息拦截.管道以层级结构的形式汇总,就创建了一个管道栈.管道栈以分层的方式进行通信并处理消息.例如 ...

  3. 【WCF】WCF中的InstanceContext与ConcurrencyMode【转】

    一.前言 最近忙于公司的在线升级项目,一个人要负责公司四大产品的在线升级,这四个产品是在Revit中以插件形式存在的,目前基于WCF来实现.等客户总量突破5万了,再重新用socket实现. 由于有服务 ...

  4. 使命必达: 深入剖析WCF的可靠会话[编程篇](上)

    在<实例篇>给出的例子中,我实际上是通过对终结点的绑定进行相应的配置让整个消息的交换过程在一个可靠会话中进行,进而实现可靠消息传输的目的.由于整个可靠会话的机制是完全在信道层实现的,而整个 ...

  5. 利用 Windows Vista 和 WCF 中强大的 P2P 通信功能[MSDN]

    点对点技术 利用 Windows Vista 和 WCF 中强大的 P2P 通信功能 发布日期: 2006-10-17 | 更新日期: 2006-10-17 Justin Smith 本文基于 Win ...

  6. 在WCF中实现双工通信(转载)

    首先声明此文章是转载博客园蒋老师之作:http://www.cnblogs.com/artech/archive/2007/03/02/661969.html 双工(Duplex)模式的消息交互方式体 ...

  7. PostgreSQL 无会话、有会话模式 - 客服平均响应速度(RT)实时计算实践(窗口查询\流计算)...

    标签 PostgreSQL , 无会话 , 客服响应速度 , 触发器 , rule , 窗口查询 背景 通常客服系统可能存在一对多,多对多的情况. 例如, 我们在使用淘宝时,与店家交流时,你根本不知道 ...

  8. 数字证书及在WCF中的应用

    一 概念 1.内容 证书的发布机构     证书的有效期     证书所有者(Subject)     签名所使用的算法     指纹以及指纹算法 公钥     私钥 2.存储区 3.有效性 二 作用 ...

  9. wcf中的使用全双工通信(转)

    wcf中的使用全双工通信 wcf中的契约通信默认是请求恢复的方式,当客户端发出请求后,一直到服务端回复时,才可以继续执行下面的代码. 除了使用请求应答方式的通信外,还可以使用全双工.下面给出例子: 1 ...

最新文章

  1. java8中的时间处理6 - 格式化
  2. Imageloader4-ImageLoader中的变量
  3. php 调用redfish,RedfishWhitePaperRedfish白皮书.pdf
  4. String和enum的互相转换
  5. Android长度单位详解(dp、sp、px、in、pt、mm、dip)
  6. windows server 2012 初安装体验
  7. 计算机组装维修中级试题,计算机维修工中级理论知识试卷.doc
  8. 归并排序 自带时间复杂度测试
  9. 八年磨一剑,阿里云ApsaraDB for HBase2.0正式上线 1
  10. How to live?
  11. How to enable/disable EWF
  12. 搜狗打不开html文件,搜狗皮肤怎么安装 安装的时候出现“无法打开此文件”
  13. EasyAR WebAR开发
  14. Echarts 柱状图上方显示数值
  15. java dh算法_java 非对称加密算法DH实现详解
  16. 计算机软件方法专利撰写,干货 | 计算机软件专利撰写模板
  17. Linux下串口调试及使用shell编程接收数据
  18. _access()函数
  19. OpenGL--摄像机漫游
  20. Android加载百度地图

热门文章

  1. Debian Linux下的Python学习——入门
  2. arm-arago-linux-gnueabi 下载,arm-arago-linux-gnueabi问题
  3. 技工学校计算机类论文,技工学校计算机教学论文
  4. php获取多个参数值,php-获取多个过滤器值参数
  5. python 描述性分析_描述性分析-1对被解释变量进行描述
  6. mysql binlog查看工具_数据同步工具otter(一)谈谈binlog和canal
  7. java 把文件打包成zip_java 文件流的处理 文件打包成zip
  8. java数组表格输出_Java 如何将数组中的数据以表格形式输出
  9. windows更改pip源_windows环境下 更换pip镜像源
  10. scrapy使用selenium抓取深圳证券交易所考评表数据