wcf学习高级篇

     代码中的所有例子都可在hi.csdn.net/heroyuchao中下载
WCF 高级篇
一、 WCF 的可靠性

首先我们得明确一点那就是网络上传送数据报是不可靠的,丢报现象时有发生,因此在WCF中对数据报传送的可靠性有特别的配制。实现可靠性的传输在WCF中是非常简单的,我们只需要在配制文件中作一些配制就行如下:

 

注意<reliableSession enable=true>,使得enable=true就行了,但是要记住不是所有的binding都可以的,目前只有三种绑定可以实现可靠传输
分别是:netTcpBindig,wsHttpBindig,wsDualHttpBinding。netTcpBindig与wsHttpBinding是默认关闭的要配制<reliableSession enable=true>
而wsDualHttpBinding是默认打开的不需要这样配制。(这种可靠性是100%的吗?学过《网络工程》的人就会知道,没有绝对可靠的协议,我相信这才是绝对的真理,呵呵)
 
一、 脱机调用服务端方法

MSMQ微软消息队列能实现一种脱机调用,因为客户端能够将信息发送到消息队列中,服务端在有空的时候再去读取消息队列中的信息,也就是说客户端的信息不必让服务端即时的处理。那么我们现在就看看在WCF中如何使用MSMQ的。还记得上一篇中的下订单的例子吗?我们继续使用这个例子,不过我要做一个小小的改动,上一篇的这个例子中,客户端调用PushOrder方法后,服务端就要马上处理把OrderID输出到控制台上。这篇中服务端不会马上处理,因为客户端可以在服务没有启动的时候调用PushOrder。只有服务在启动完才会把OrderID输出。由于我用的系统是XP,而XP默认是没有安装MSMQ的,所以我们可以在“添加删除程序中安装”方法与安装IIS是一样的。安装完成后我们在计算机管理找到消息队列。

安装一个专用队列如下所示:

前面的private$表示这个是专用队列,这里我们创建一个myprivatequeue队列并在事务性那打个勾,因为这样我们就能保证发送信息与接收信息的顺序是一样的,完成这个工作后我们再来看看服务端的代码:

代码与上一篇中基本上是一样的,唯一不同点是我们的pushorder方法上多了个IsOneWay=true,在默认情况下IsOneWay是为false的,也就是说默认情况下是双工通信,为什么我们在这里将它设为true呢?设为true后双工就变成单向了,因为客户端在调用方法时服务端是可以没有启用的,如果是双向通信,客户端在服务端没有启动时调用方法会抛出异常,但是设为true后我们就是告诉程序,我们不需求要知道调用的结果,因此客户端就能正常调用没有启动的服务器方法了。下面我们再看看配制文件:

这个配制文件有点多但是不复杂,先看看第一个endpoint,由于我们要使用MSMQ,所以我们就只使用netMsmqBinding,所以address就变成了:

net.msmq://localhost/private/myprivatequeue,其中private表示是专有队列,myprivatequeue是队列的名字,localhost是本机,如果队列是其它计算机中的,只要把localhost改成装有队列的计算机IP或计算机名就行。那第二个endpoint与第三个endpoint的作用呢?我们知道服务端只有将contract暴露后客户端才能下载到,暴露元数据我们必须用mex系列的绑定,而mex是成队使用的如第二个endpoint中的wsHttpBindingmexHttpBinding就是一对。而netMsmqBinding没有与它对应的mex绑定,所以我就加了后两个endpoint,这样客户端就能通过http下载到代理了。

再看看客户端的调用代码:

 

为什么我们的构造函数中有个“NetMsmqBinding_MyService”呢?在上一篇中我们知道如果有多个endpoint时我们就要选一个endpoint而完成调用。而netmsmqbinding_myservice就是选用MSMQ绑定的endpoint的,大家看看客户端的下载到代理后的配制文件就知道了。
我们可以在不启动服务端时调用方法,后启动服务就能看到刚刚客户端的调用结果了。
 
一、 回调客户方法
回调客户方法我们在WebService是很难实现的,但是Remoting是很容易实现的,因为在Remoting中可以引用传递对象。下面我们看看如何在WCF中实现回调客户方法的。
回调的方法一定是在客户实现的,在服务端声明的,因为我们可以把回调方法的声明放到一个接口的定义中,因此这个接口就是回调契约,那么这个回调方法就是方法契约了。有了这点说明后,我们再看看代码:

首先我们定义了一个回调接口ICallback,在接口中我定义了回调方法Notify,但是我们的服务部分并没有实现,因为这个方法的实现会在客户端完成。Service Contract中我们只有一个方法Login,这个方法会向服务端的控制台输出有新客户端登录的信息,同时调用调用登录后的所有以登录后的客户端回调方法,其中所以回调方法的调用通道都放到了list中。看看配制文件:

在这里我们使用了netTcpBinding,这有没有它的必有性呢,使用Tcp是很必要的,因为服务端要回调客户端方法就要求通道是双向通信的。

这个客户端代码:

 

客户端我们实现了notify访求,同时在构造client对象是我们要创建一个实例上下文对象,同时向服务端传递实现了notify方法的对象。
运行服务端再启动客户端,我们会看到服务端有新用户登录的通知,但是这个客户端没有任何通知,我们再启动一个客户端,这时上一个客户端就会收到新用户登录的通知了。
注意,回头看看服务端的代码在login方法中我发现一个非常严重的BUG
callback.Notify(); 为什么是BUG,就留给大家思考了。(本示例来自微软中国的WCF培训视频)
 
一、 分布式事务
我们先来看看一个场景:我们从招商银行转500元钱到中国银行中,这里必须完成两步操作,首先从招行的帐号中扣500,其次在中国银行的帐号中加上500,同时这两步的操作必须都完成或都不完成,我们绝对不允许招商的帐号上扣了钱但是中行的帐号上没有加钱,也不允许中行的帐号上加了钱而招行的帐号上没有扣钱,而招行与中行的帐户表一定是放到不同服务器的不同数据库存中,所以这时我们就不能简单的使用本地事务来完成操作,必须使用分布式事务。这个场景将作为本节的例子代码,但是现在我们先来看看.net类库中Transaction的命名空间。
NET Framework 2.0 版包含一个新的事务框架,可以通过 System.Transactions 命名空间访问。此框架公开事务的方式是完全集成在 .NET Framework 中,并包含 ADO.NET。
除了对编程能力的增强之外,System.Transactions 与 ADO.NET 一起使用,可以在处理事务时协调优化。可提升事务是可以根据需要自动提升为完全分布式事务的轻型(本地)事务。
在 ADO.NET 2.0 中,System.Data.SqlClient 增加了在使用 SQL Server 2005 时对可提升事务的支持。除非需要添加系统开销,否则,可提升事务不会调用分布式事务的“添加系统开销”。可提升事务是自动的,不需要开发人员参与。
只有在 SQL Server 2005 中使用 SQL Server .NET Framework 数据提供程序 (SqlClient) 时,才可以使用可提升事务。
分布式事务通常占用大量的系统资源,通过 Microsoft 分布式事务协调程序 (MS DTC) 管理,该协调程序集成了事务中访问的所有资源管理器。可提升事务是 System.Transactions 事务的一种特殊形式,有效地将工作委托给简单的 SQL Server 2005 事务。System.Transactions、System.Data.SqlClient 和 SQL Server 2005 协调在处理事务时涉及到的工作,根据需要将其提升为完全分布式事务。
使用可提升事务的优点是在使用活动 TransactionScope 事务打开某个连接并且不打开任何其他连接时,事务作为轻型事务提交,而不引发完全分布式事务的其他系统开销
使用TransactionScope的一般代码格式是这样的:
Using(TransactionScope cope=new TransactionScope())
{
   …
   cope.Commit();
}
这里我们要讲下TransactionScope的构造函数
public TransactionScope (
    )
TransactionScopeOption 是一个枚举类型有下三个值:
Required: 该范围需要一个事务。如果已经存在环境事务,则使用该环境事务。否则,在进入范围之前创建新的事务。这是默认值。
RequiresNew: 总是为该范围创建新事务。
Suppress: 环境事务上下文在创建范围时被取消。范围中的所有操作都在无环境事务上下文的情况下完成。
 
通过这些值我们就知道事务是可以传播的,但是WebSerivce与Remoting都是不支持事务的传播,这种分布是事务只能是在com+中得以实现,但是引入的WCF后我们也能够轻松实现分布式的事务。
 
回到场景

我们先来看看“招行”的服务代码:

 
代码中只有一个 Substract string account,int money
       其中 account 表示帐号 money 表示要扣的金额数 , 扣钱成功后会返回 true 失败会返回 false
在这里我主要介绍下 TransactionFlow (TransactionFlowOption.Allowed)
OperationBehavior (TransactionScopeRequired = true)
TransactionFlow (TransactionFlowOption.Allowed) 表示方法允许事务,其中TransactionFlowOption有三个值:
Allowed: 事务是被允许的
Mandatory: 必须有事务,如果没有事务会抛出异常
NotAllowed: 事务是不允许的
OperationBehavior (TransactionScopeRequired = true): 表示该方法内在操作都会在一个事务中执行。

为了能使事务能传播,我们必须在配制文件中作一些配制:

 

transactionFlow=true 就表示事务是可以传播的。注意:不是所有的绑定都能使用事务的,我们称可以使用事务的绑定为事务敏感,我这里目前没有完全收集所有的事务敏感绑定,在使用分布时我们最好上网查查。
 
再看看“中行”的代码:
 
这段代码就是完成了加钱的操作,至于配制文件与上面的一样,只是绑定的端口不同而已。
客户代码:
 
客户首先定义了一个事务范围,在这个范围内完成扣钱与加钱的操作,只有两个操作都成功后才完成事务的提交,在这里我特别对分布式事务的性能作了一下测试 , 通过 ticks 值我发现使用分布事务后会比不使用分布式事务慢 10 倍以上,所以我们要慎重考虑是否有使用分布式事务的必要性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值