转载地址:http://blog.csdn.net/tcjiaan/article/details/8281782

每个客户端在服务器上都有其的独立数据存储区,互不相干,就好像A和服务器在单独谈话一样,所以叫会话

下面,我们写一个例子,看看在不支持会话的绑定上连续调用两个有关联的代码,会发生什么情况。

    [ServiceContract]
public interface IService
{
[OperationContract(IsOneWay = true)]
void SetValue(int n);
[OperationContract]
int GetValue();
} [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class MyService : IService
{ public MyService()
{
Console.WriteLine("-------------------------------");
Console.WriteLine("{0} - 服务被实例化。",DateTime.Now.ToLongTimeString());
}
// 在析构函数中也输出信息
~MyService()
{
Console.WriteLine("{0} - 服务实例被释放。", DateTime.Now.ToLongTimeString());
Console.WriteLine("--------------------------------");
} /// <summary>
/// 私有字段
/// </summary>
private int m_Value = int.MinValue; public void SetValue(int n)
{
this.m_Value = n;
Console.WriteLine("会话ID:{0}", OperationContext.Current.SessionId);
} public int GetValue()
{
Console.WriteLine("会话ID:{0}", OperationContext.Current.SessionId);
return this.m_Value;
}
}

在服务类中,我们分别在构造函数和析构函数中输出一些内容,以便于在运行时看到服务什么时候被实例化,什么时候被释放。同时,在调用每个操作协定时,我们也输出当前会话的ID,如果空就说明当前没有启用会话。

接着,实现服务主机,我们使用不支持的Bindding。

        static void Main(string[] args)
{
Console.Title = "WCF服务器端";
using (ServiceHost host = new ServiceHost(typeof(MyService), new Uri("http://127.0.0.1:1211/sv")))
{
// 绑定
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.None;//不需要安全模式
host.AddServiceEndpoint(typeof(IService), binding, "/ep");
// 服务元数据
ServiceMetadataBehavior mb = new ServiceMetadataBehavior();
mb.HttpGetEnabled = true;
mb.HttpGetUrl = new Uri("http://127.0.0.1:8008/meta");
host.Description.Behaviors.Add(mb);
host.Opened += (sender, arg) =>
{
Console.WriteLine("服务已启动。");
};
try
{
host.Open();//打开服务
Console.Read();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

然后,实现客户端,为了使演示操作更方便,客户端使用Windows Forms项目,界面大致如下图所示,源代码我后面会上传到资源。

服务有两个操作,从前面服务类的定义我们知道,我在服务类内部定义了一个私有字段,而公开的两个操作协定,分别是设置这个值和获取这个值。

    public partial class Form1 : Form
{
WS.ServiceClient client = null;
public Form1()
{
InitializeComponent();
client = new WS.ServiceClient();
// 关闭通道
this.FormClosing += (frmsender, frmargs) => client.Close();
} private void btnCall1_Click(object sender, EventArgs e)
{
int v;
if (!int.TryParse(this.txtInput.Text, out v))
{
return;
}
client.SetValue(v);
} private void btnCall2_Click(object sender, EventArgs e)
{
int v = client.GetValue();
this.txtOutput.Text = v.ToString();
}
}

我们现在要测试一下,看看先后调用这两个方法,能不能得到我们预期的值。即如果我调用SetValue(100),那么,在调用GetValue时应该返回100,事实是不是这样呢?

八格牙路,我没有看到预期的值。

我输入了100,可是取出来的是Min int,再看一看服务器端输出了哪些信息。

很明显,每调用一次操作,服务类就被实例化一次,意思就是:调用SetValue时是实例A,而调用GetValue时可能是实例B了,所以,私有字段的值没有被保存。

那么,如何证明两次调用的操作不属于同一个服务实例呢?还记得GetHashCode吗?对的,只要在内存中不是同一个实例的,其哈希值肯定不同。是不是这样呢,我们把上面的服务代码改一下。

        public void SetValue(int n)
{
this.m_Value = n;
Console.WriteLine("------------------------");
Console.WriteLine("当前实例的哈希值:{0}", this.GetHashCode().ToString("x"));
Console.WriteLine("会话ID:{0}", OperationContext.Current.SessionId);
} public int GetValue()
{
Console.WriteLine("------------------------");
Console.WriteLine("当前实例的哈希值:{0}", this.GetHashCode().ToString("x"));
Console.WriteLine("会话ID:{0}", OperationContext.Current.SessionId);
return this.m_Value;
}
 

那么,这次又会发生什么事呢,看结果。

这个结果证实了我之前的推断,先后调用的两个方法不是同一个实例的。

那么,如果启用了会话,结果又会如何呢?

在定义服务协定的时候,设置SessionMode可以让服务要求客户端启用会话。

接下来,要使用支持会话的绑定。

把客户端的服务引用更新一下。然后看看这回会不会达到我们的目的。

怎么样,高兴吧?终于看到我们要的效果了,我输入了100,取出来的还是100,这一回从服务器端的输出看,服务类只被实例化了一次,而且看看两个哈希值是相同的,这证明了确实是同一个实例,同时,我们也看到了两次调用的会话ID是一样的,这也说明了,客户端两次调用都基于同一个会话进行的,这么一来,输进去的100就能顺利取出来了。

你不妨多开几个客户端来试试。

看到那个不同的会话ID,哈希值和实例化时间了吧?这表明了:服务器独立维护着与每个客户端的会话

下面还要对我们的解决方案进行修改。

服务器端,把服务协定改为:

在服务类中增加对EndSession方法的实现。

看到变化了吗?

我们在使用OperationContractAttribute定义操作协定时,设置了两个属性:

a、IsInitiating:如果为真,则当调用该操作时就启用会话。

b、IsTerminating:如果为真,则说明当该用该操作时终结会话。

所以,上面的例子是,当调用SetValue时开始会话,当调用EndSession方法后会话结束,在选择作为结束会话的方法时,最好使用返回值为void或者单向通讯(One Way)的方法,这样,不用等待客户结束才结束会话,因为单向通讯,不需要向客户端回复消息,因为它被调用后就可以马上终止会话了。

在客户端代码中,我们要取消之前的关闭通道的代码,因为不再需要,会话一旦终结,通道就自动关闭,服务实例就会自动人间消失。

        WS.ServiceClient client = null;
public Form1()
{
InitializeComponent();
client = new WS.ServiceClient();
// 关闭通道
//this.FormClosing += (frmsender, frmargs) => client.Close();
}
 

然后,在调用完GetValue后马上就EndSession,看看这回又会发生什么。

这样,一旦三个方法调用完之后,会话结束,服务实例也解放了。

再说明一下,IsInitiating = true的操作开始新会话,IsTerminating = true的操作终结会话

重温WCF之会话Session(九)的更多相关文章

  1. WCF会话(Session)与实例(Instance)管理

    一.理解Session 1.Session的作用:保留Client和Service之间交互的状态,确保Client与Service之间交互唯一性(SessionId),即:多个Client同时访问Se ...

  2. WCF技术剖析之九:服务代理不能得到及时关闭会有什么后果?

    原文:WCF技术剖析之九:服务代理不能得到及时关闭会有什么后果? 我们想对WCF具有一定了解的人都会知道:在客户端通过服务调用进行服务调用过程中,服务代理应该及时关闭.但是如果服务的代理不等得到及时的 ...

  3. 简单PHP会话(session)说明

    现在程序员愈发的不容易了,想要精通,必然要寻本溯源,这其实与目前泛滥的愈发高级的语言以及众多的框架刚好相反,因为它们在尽可能的掩盖本源使其简单,个人称之为程序员学习悖论. 注:作者接触web开发和ph ...

  4. http 会话(session)详解

    会话(session)是一种持久网络协议,在用户(或用户代理)端和服务器端之间创建关联,从而起到交换数据包的作用机制 一.查看session id 可利用相关工具,比如firebug,httpwatc ...

  5. Tensorflow会话Session

    转载自: http://blog.csdn.net/Hanging_Gardens/article/details/72784392 https://www.cnblogs.com/hypnus-ly ...

  6. 网络基础 http 会话(session)详解

    http 会话(session)详解 by:授客 QQ:1033553122 会话(session)是一种持久网络协议,在用户(或用户代理)端和服务器端之间创建关联,从而起到交换数据包的作用机制 一. ...

  7. Java通过遍历sessionId获取服务器所有会话session

    Servlet2.1之后不支持SessionContext里面getSession(String id)方法,也不存在遍历所有会话Session的方法.但是,我们可以通过HttpSessionList ...

  8. jfc在jsp页面画图,不将图片存在服务器端,只存入会话session(可用)

    jfc在jsp页面画图,不将图片存在服务器端,只存入会话session.其中主要用到jfc的一个servlet类. <%@ page contentType="text/html;ch ...

  9. Oracle数据库的连接模式connection Mode、连接connection与会话session

    数据库的连接模式Connection Mode: Dedicated Server Mode(专有模式) 当用户发出请求时,如远程的client端通过监听器连接数据库上,ORACLE的服务器端会启用一 ...

随机推荐

  1. 学号160809224姓名黄家帅c语言程序设计实验2 选择结构程序设计

    实验2-1 输入3个数,并按由大到小的顺序输出. 实验要求: 编写一个C程序,输入3个数,并按由大到小的顺序输出. 源码: #include <stdio.h>void main(){ i ...

  2. 两轮自平衡小车双闭环PID控制设计

                                                                                            两轮自平衡小车的研究意义 ...

  3. 3.2---最小栈(CC150)

    //思路:入栈时不是最小值,永远都没机会成为最小值. import java.util.Stack; class MinStack { private Stack<Integer> sta ...

  4. django xadmin 插件(1)

    1. 插件的作用可以是全局的,也可以是只针对某个模型的.通过其 init_request控制是否加载此插件, demo如下: class SCPCardOverviewPlugin(BaseAdmin ...

  5. Python核心编程这本书的一些错误

    <Python核心编程第二版>这本书比<Python基础教程第二版修订版>详细很多,丰富了很多细节,虽然它是一本经典的入门书,但我发现还是存在一些明显的错误.在面向对象编程这一 ...

  6. NFV技术中遇到的新名词

    NUMA topology:Non-Uniform Memory Access (NUMA) is a computer system architecture that is used with m ...

  7. 一个简单的任务执行时间监视器 StopWatch

    有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,然后这样如果执行大量测试的话就很麻烦,并且不直观, 如果想对执行的时间做进一步 ...

  8. [转]servlet的执行原理与生命周期

    一.先从servlet容器说起:大家最为熟悉的servlet容器就是Tomcat ,Servlet 容器是如何管理 Servlet? 先看一下tomcat的容器模型: 从上图可以看出 Tomcat 的 ...

  9. [转]Java 征途:行者的地图

    前段时间应因缘梳理了下自己的 Java 知识体系, 成文一篇望能帮到即将走进或正在 Java 世界跋涉的程序员们. 第一张,基础图 大约在 2003 年我开始知道 Java 的(当时还在用 Delph ...

  10. .NET中六个重要的概念:栈、堆、值类型、引用类型、装箱和拆箱 (转)

    作者: Edison Chou  来源: 博客园  发布时间: 2014-09-03 15:59  阅读: 318 次  推荐: 2   原文链接   [收藏]   原文作者:Shivprasad k ...