Windows Communication Foundation (Workshop)
原文以及代码下载
推荐阅读:服务设计原理:服务模式和反模式
Part 2:在WCF中操作会话
作者Robert Shelton, Jr.
译者LoveCherry
在WCF Workshop的Part 2中,我们来研究如何操纵服务的会话状态。
完成这个workshop需要的东西
占位
从哪里获取源代码和最新资料
占位
目标…[见此系列的Part 1]
占位
更新后的目标…[针对此系列的Part 2]
在Part 1中,我们达到了最基本的目标:建立一个WCF服务和关联的客户端,但是我们注意到余额没有正常地更新。在Part 1的最后我也说过了,如果我们使用一个数据库(持久的存储空间)的话就能解决这个问题,这对于“现实世界中”需要长期存储数据的情况是非常有必要的。然而,为了Part 1和Part 2的简单我们没有使用数据库,这意味着我们只能通过使用“会话”来存储状态(或数据)。对于短期的存储这还可以(比如说放在用户会话中),但要说明的是,对于真正的应用程序,还是需要建立一个数据库来保存数据。
也就是说此系列的Part 2将会告诉大家如何去开启会话,并研究相关的选项。
应用场景[见此系列的Part 1]
占位
回顾Part 1: SO(A/D)的四大原则
占位
系统构架图
占位
进行编码…(我们要做什么和为什么要这么做)
步骤:为契约开启会话
做什么:我们需要做的第一件事情就是告诉WCF,让它在用户使用银行帐户服务的时候给客户端分配一个SessionID。通过在契约顶部(在本例中就是那个接口)的ServiceContract属性上添加(Sessions=True)参数来实现。
为什么:在Part 1中我已经说过了,一个WCF服务可以有一个或多个服务契约,我们可以灵活地在每个服务上设置一些选项,比如说是否支持会话等等。因此,我们必须明确指定哪些契约支持会话哪些又不支持。
步骤:
- 打开BankServices解决方案
- 接下来,打开BankServices.cs文件(在App_Code文件夹中)
- 现在,为ServiceContract 属性添加(Sessions=True)参数
你的代码应该如下:
步骤:选择你想要的会话状态的类型
做什么:为了能让系统保留每个独立用户在进行银行业务后银行帐户的余额,我们需要为服务开启“会话”。但现在我们不打算把这些银行业务存入数据库进行长期存储,因此当用户结束他们的银行业务或者会话超时的时候这些信息会丢失。
在我们考虑为我们的服务使用哪些会话选项以前,让我们先花一分钟时间看一下WCF支持哪些“会话”或“会话状态”。在继续以前我还想改下措辞,其实在WCF中,“会话”这个概念精确地说应该称作“实例上下文(Instance Context)”。
WCF支持如下的会话状态(和定义):
- Per Call [InstanceContextMode.PerCall]:如果我们希望用户每一次调用服务系统都分配一个新的SessionID的话可以使用这个选项。但是在我们的这个例子中不是很合适,因为我们需要保留用户每次操作后的余额。
- Per Session [InstanceContextMode.PerSession]:如果我们希望为每一个用户分配一个独立的SessionID实现在每次调用后保留信息的话可以使用这个选项。WCF会确保每个用户有不同的SessionID。对于我们的服务,这是最佳选择了,这样对于在用户的每次调用后系统都能保留帐务余额。
- Shareable [InstanceContextMode.Shareable]:使用这个选项的话,系统会为每一个会话新建一个SessionID并在多个会话中共享。我认为这和ASP.NET的Application变量有点类似。当我们需要在系统中存储信息以便每一个连接到服务的用户使用的话,就可以使用这个选项了。
- Single [InstanceContextMode.Single]:使用这个选项的话,所有客户端会使用一个SessionID。这和前面的“Shareable”有点不同,“Shareable”会有可供多个客户端间访问的SessionID,而对于“Single”所有用户都用同一个SessionID。
为了完整性,我还需要在这里提一下Web服务安全对话(WS-SecureConversation)和Web服务可靠消息传送(WS-ReliableMessaging)。在讨论这两种标准的时候我们也经常用“会话”这个词,但是它和我们workshop中说的这个“会话”有点不同。我们说的会话是在类&方法级别的,然而安全对话和可靠消息发生在服务的传输级别。MSDN中有很多介绍WCF是怎么样支持这两种安全标准的文章,我强烈建议大家看一下。
为什么:前面说过,我们要为我们的程序在类层次上实现“Per Session”实例化模式,这样AccountActivities类的每个方法都将实现这个模式。
你的代码应该如下:
步骤:设置会话的Initialization和Termination [可选]
做什么:还有一个WCF支持的有关会话的特性就是能指定哪些方法能初始化一个会话哪些方法能终止会话。可以通过在[OperationContract] 属性中添加参数来实现。
我们有这些选择:
IsInitiating=True/False:如果你希望一个方法的调用者来初始化会话(比如,使用户获取一个分配的SessionID)可以设置这个选项为True,反之,如果不希望它初始化会话就设置为False。
IsTerminating=True/False:如果你希望一个方法的调用者来关闭会话并且释放SessionID的话可以设置这个选项为True,反之,如果不希望这么做的话可以设置为False。
你同样能为某个方法设置这些选择组合,代码如下:
[OperationContract(IsInitiating=True, IsTerminating=True]
public void Foo()
这样Foo()方法会建立和终止SessionID。
或者,
[OperationContract(IsInitiating=True, IsTerminating=False]
public void Foo()
这样Foo()方法会建立SessionID,但是终止操作会由其它方法实现,或者到了会话过期时间才过期。
为什么:在我们的例子中不需要设置这些参数,因为默认的行为能满足我们的要求:IsInitiating=True, IsTerminating=False(如果你从来没有改变过参数的话)
因此,你的代码应该还是如下:(没有改动)
步骤:测试我们更新后的服务
做什么:我们要测试服务来确保它正常监听,因为就算成功编译后还会有很多错误。
为什么:Part 1中我说过,没有客户端的话确实没有什么简单的方法来测试我们服务中的业务逻辑,因此我们在部署前所能做的也仅有测试服务端点(EndPoint)来保证服务能启动并正常响应。
步骤:
- 编译并运行服务
如果一切正常,屏幕应该显示如下:
步骤:部署更新后的服务
做什么:既然我们知道我们的服务至少能监听一个我们建立的端点(URL地址),我们接下来部署服务。
为什么:每次我们更新服务增加了一些行为和业务逻辑后必须把它重新部署到应用程序服务器(本例中为IIS)。
步骤:
- 第一步,让我们选择Build Menu菜单的Publish Web Site选项
- 我们的目标URL:http://localhost/services/bankaccountservices应该还在目标文本框内,如果没有的话请重新输入一次。
屏幕应该显示如下:
- 点击OK按钮开始部署。
- 如果做过Part 1中的例子或者以前部署过这个服务的话,你会看到下面的提示:
- 点击Yes继续,“覆盖”以前的网站。
- 从IDE中你应该能得到一个“Publish Succeeded”的消息,如果没有的话,请检查所有步骤并确保IIS已经正确配置为ASP.NET2.0。
步骤:更新客户端来使用更新后的服务
做什么:接下来,我们需要更新客户端来使用我们的服务。
为什么:这步操作会确认服务代理代码,来检查我们客户端应用程序中使用的更新后的方法、端点是否还有效。
步骤:
- 打开ATM客户端项目
- 删除app.config。尽管这步不是必须的,但我发现每次更新客户端的时候VS2005都会新在app.config中增一个节点而不是替换原来的。
- 现在,通过重新连接服务并得到最新的配置方案和代码代码来更新客户端。
o 右键点击ATMServices.map文件
o 点击“Update Service Reference”选项
o 这样,客户端就会联系服务来更新自身并且新建一个app.config。
我们的解决方案看上去应该如下:
步骤:使用ATM客户端测试更新后的服务
做什么:现在是测试我们客户端和更新过的服务的时候了。
为什么:我们要看看是否它能在每次调用后保留余额。
步骤:
- 编译并运行ATM客户端
界面如下:
- 让我们点击ATM上的按钮并按Enter来试着往帐户中存入$100.00。
应该显示如下:
- 让我们点击ATM上的按钮并按Enter来试着往帐户中再存入$100.00,来看看现在在调用后余额是否能保存。
应该显示如下:
- 让我们从帐户中提出$100.00。
- 点击Withdrawals页
- 使用ATM按钮输入$100并按Enter,来看看在调用后余额是否能保存。
应该显示如下:(如果一切正常的话余额应该回到$100)
Part 2结束语