WCF把书读薄(3)——数据契约、消息契约与错误契约

  真不愧是老A的书,例子多,而且也讲了不少原理方面的内容,不过越读越觉得压力山大……这次来稍微整理整理事务和可靠会话的内容。

  

  十八、事务编程

  WCF的分布式事务编程,指的是在客户端定义一个事务范围,在这个范围内对WCF服务进行连续调用,可以实现其中一个出现问题整体回滚的效果。由于WCF依赖于MSDTC,所以首先需要开启MSDTC服务才能够通过WCF进行分布式事务编程。

  这里我也自己写了一个典型的银行转账的练习,首先需要建立一个数据库,数据表只有一张Account表,其中有AccountId和Money两个int型字段,AccountId为主键。里面有两个账户:账户1有1000,账户2有1000。

  首先,既然是分布式事务,事务需要从客户端流转到服务端,那么它们之间就应该达成“共识”,也就是说需要对服务契约做手脚。下面定义一个服务契约:

[ServiceContract(SessionMode = SessionMode.Required)]
public interface IBankService
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
void OutMoney(int fromAccountId, int money); [OperationContract]
[TransactionFlow(TransactionFlowOption.Mandatory)]
void InMoney(int toAccountId, int money);
}

  在转账的整个过程当中,用户首先发送一个OutMoney请求,减少账户1当中的钱,之后发送InMoney请求,增加账户2的钱。显然这个契约需要一个会话,所以给服务契约增加SessionMode属性。注意,在实际应用当中转账应该作为一个完整的服务而不是两个服务方法,这里只是举个例子而已。

  事务的流转是一个操作行为,所以需要在操作契约上增加TransactionFlow标记,并设置TransactionFlowOption的值,这个标记是事务的总开关。其值有三个:NotAllowed(默认值,客户端事务禁止通过该方法流入服务端),Allowed(允许流入事务),Mandatory(必须在事务内调用),这里将转账操作设置为必须在事务内。

  由于事务操作必然伴随着消息交换,所以OneWay操作必然是不支持事务的,即OneWay操作的TransactionFlowOption只能为NotAllowed(下P143)!

  接下来实现这个服务操作,代码如下,其中Repository细节就不贴了:

[ServiceBehavior(TransactionIsolationLevel = IsolationLevel.Serializable,
TransactionTimeout = "00:05:00",
TransactionAutoCompleteOnSessionClose = true)]
public class BankService : IBankService
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)]
public void OutMoney(int fromAccountId, int money)
{
try
{
AccountRepository repository = new AccountRepository();
Account accOut = repository.GetAccountById(fromAccountId);
accOut.Money -= money;
repository.Save(accOut);
}
catch (Exception ex)
{
System.Transactions.Transaction.Current.Rollback();
throw new FaultException(new FaultReason(ex.Message));
}
} [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void InMoney(int toAccountId, int money)
{
try
{
AccountRepository repository = new AccountRepository();
Account accIn = repository.GetAccountById(toAccountId);
accIn.Money += money;
repository.Save(accIn);
}
catch (Exception ex)
{
System.Transactions.Transaction.Current.Rollback();
throw new FaultException(new FaultReason(ex.Message));
}
}
}

  服务操作的执行是否需要自动登记到事务当中,以及服务操作何时提交,是服务端自己说了算的,所以要在具体的操作上设定操作行为。这里我们用到两个行为:TransactionScopeRequired和TransactionAutoComplete,它们都是布尔值,前者用于决定操作是否纳入事务内,默认为false,这里需要设置为true,后者用于决定该操作执行完毕后是否提交事务,于是在第一个操作上设置为false,第二个操作设置为true。

  在ServiceBehavior上可以设定事务的行为,

  最后需要在事务抛异常的情况下回滚。TransactionIsolationLevel用于指定事务隔离级别,默认是Serializable,TransactionTimeout不解释,TransactionAutoCompleteOnSessionClose表示在会话正常结束时是否自动提交事务,默认为false,另外还有一个ReleaseServiceInstanceOnTransactionComplete,表示当事务完毕时是否需要释放服务实例,默认为false。

  写完了服务端代码就该改XML了,XML如下:

<configuration>
<system.serviceModel>
<bindings>
<ws2007HttpBinding>
<binding name="transactionalTcpBinding"
transactionFlow="true" />
</ws2007HttpBinding>
</bindings>

<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:9527/bankservice/metadata" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Bank.Service.BankService" behaviorConfiguration="metadataBehavior" >
<host>
<baseAddresses>
<add baseAddress="http://127.0.0.1:9527/"/>
</baseAddresses>
</host>
<endpoint address="bankservice"
binding="ws2007HttpBinding"
bindingConfiguration="transactionalTcpBinding"

contract="Bank.Interface.IBankService" />
</service>
</services>
</system.serviceModel>
</configuration>

  WCF是否有能力流转事务以及事务按照怎样的协议流转,是绑定控制的。在WCF当中,除了BasicHttpBinding、NetMsmqBinding和MsmqIntegrationBinding外,都是支持事务传播的(下P145),即便支持事务,事务流转也是默认关闭的,所以需要配置绑定的transactionFlow属性。这里使用了ws2007HttpBinding,并将其transactionFlow属性设置为true。

  发布服务后,在客户端使用如下代码调用服务:

static void Main(string[] args)
{
BankServiceClient proxy = new BankServiceClient(); using (TransactionScope transactionScope = new TransactionScope())
{
try
{
proxy.OutMoney(, );
proxy.InMoney(, );
transactionScope.Complete();
}
catch (Exception ex)
{
(proxy as ICommunicationObject).Abort();
}
}
}

  这里定义了一个事务范围,并且在最后提交了事务,如果出现异常,则关闭服务代理。这样,在服务过程当中如果出现了异常,事务就会回滚了。

  十九、可靠会话

  这次真的是名副其实地把书读薄了!下册书上全是原理,嗯,这里不抄原理,只用来拷代码,不过发现书上木有太多现成可用的代码,于是就稍微总结总结好了。所谓可靠会话就是用于保证消息传递有效、有序、不重复的一套机制,WCF对这套机制的实现体现在一个叫ReliableSessionBindingElement的绑定元素上,所以要实现可靠会话,可以修改绑定,或者手写绑定。

  典型的应用就是文件分段传输,如果不实现可靠会话,分段传输就可能发生丢包、接收发送顺序不一致和重复发送的问题。

  WCF已经为我们提供了很多支持可靠会话的内置绑定,其中wsHttpBinding、wsFederationBinding、netTcpBinding的可靠会话功能是默认关闭的,wsDualHttpBinding和netNamedPipesBinding是默认开启的。

  启动可靠会话很简单,只要在绑定里加上配置:

<bindings>
<netTcpBinding>
<binding name="reliableNetTcpBinding">
<reliableSession enabled="true"/>
</binding>
</netTcpBinding>
</bindings>

并且在终结点的bindingConfiguration属性指定这个绑定配置就行了。需要注意客户端和服务端的绑定配置要一致。  

  这个绑定配置节有几个属性,参考http://msdn.microsoft.com/zh-cn/library/ms731302.aspx,可以用于做负载控制,不过无论如何,ordered要设置为true才能开启可靠会话(P255)。

  另外,如果我们需要某个服务操作必须要保证有序性才能被执行,则需要在ServiceContract接口定义上多打上一个反射标签:

[DeliveryRequirements(RequireOrderedDelivery = true)]

这样一来,如果没有在服务行为上配置有序,则host时会报异常。

WCF把书读薄(4)——事务编程与可靠会话的更多相关文章

  1. WCF把书读薄(3)——数据契约、消息契约与错误契约

    上一篇:WCF把书读薄(2)——消息交换.服务实例.会话与并发 十二.数据契约 在实际应用当中数据不可能仅仅是以int Add(int num1, int num2)这种简单的几个int的方式进行传输 ...

  2. WCF把书读薄(2)——消息交换、服务实例、会话与并发

    上一篇:WCF把书读薄(1)——终结点与服务寄宿 八.消息交换模式 WCF服务的实现是基于消息交换的,消息交换模式一共有三种:请求回复模式.单向模式与双工模式. 请求回复模式很好理解,比如int Ad ...

  3. WCF学习笔记之事务编程

    WCF学习笔记之事务编程 一:WCF事务设置 事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元: WCF通过System.ServiceModel.TransactionFlowA ...

  4. [WCF编程]12.事务:服务事务编程(下)

    一.投票与提交 虽然WCF负责事务传播及两阶段提交协议的管理工作,但是 她不知道事务是否应该提交或终止.这需要根服务告诉WCF应该何时启动两阶段提交协议.是提交还是终止.WCF提供了两种编程模式来对事 ...

  5. WCF分布式开发步步为赢(12):WCF事务机制(Transaction)和分布式事务编程

    今天我们继续学习WCF分布式开发步步为赢系列的12节:WCF事务机制(Transaction)和分布式事务编程.众所周知,应用系统开发过程中,事务是一个重要的概念.它是保证数据与服务可靠性的重要机制. ...

  6. [WCF编程]12.事务:服务事务编程(上)

    一.设置环境事务 默认情况下,服务类和操作没有环境事务,即使客户端事务传播到服务端也是如此. 尽管强制事务流从客户端传播过来,但服务端的环境事务依旧为null.为了启用环境事务,每个操作必须告诉WCF ...

  7. MySQL基础之事务编程学习笔记

    MySQL基础之事务编程学习笔记 在学习<MySQL技术内幕:SQL编程>一书,并做了笔记.本博客内容是自己学了<MySQL技术内幕:SQL编程>事务编程一章之后,根据自己的理 ...

  8. WCF分布式开发步步为赢(4):WCF服务可靠性传输配置与编程开发

    今天继续WCF分布式开发步步为赢系列的第4节:WCF服务可靠性传输配置与编程开发.这个章节,我们要介绍什么是WCF服务的可靠性传输,随便介绍网络协议的概念,Web Service为什么不支持可靠性传出 ...

  9. WCF学习笔记之可靠会话

    可靠会话传输需要解决两个问题:重复消息和无序交付:制定WS-RM的一个主要目的就是实现一种模块化 的可靠消息传输机制:WS-RM两个版本(WS-RM1.0和WS-RM1.1): WCF中整个可靠会话的 ...

随机推荐

  1. SEO优化---10分钟学会建立高转化率的网站关键词库

    想要优化好一个网站,行业的分析,以及关键词的挖掘是必要的,有一定的关键词排名了,但是转化率和流量方面却很不理想这种情况大部分是只注重了有指数的关键词排名,而忽略了长尾关键词和一些没有指数但是可以带来巨 ...

  2. 常用JavaScript操作页面元素的方法

    1.取得dropdownlist的选中值 var ddl =document.getElementById('<%=ddlusers.ClientID%>'); var index = d ...

  3. WM_COMMAND 和 WM_NOTIFY 的区别

    当我们按下一个菜单选项,或者一个控件需要通知父窗口一个事件发生(如鼠标单击.双击等),或者快捷键被按下时,Windows将会发送一个 WM_COMMAND 消息给父窗口.那么 WM_COMMAND 消 ...

  4. php excel 设置单元格格式为文本格式

    学习源头:https://www.cnblogs.com/php-linux/p/6179442.html 解决 PHPExcel 长数字串显示为科学计数 在excel中如果在一个默认的格中输入或复制 ...

  5. Nginx安装过程

    1. 首先 ./configure --prefix=/usr/common/nginx --with-http_stub_status_module 报如下错误: 2. 从报的错可以看出缺少pcre ...

  6. (转)c#实现开机自启动

    RegistryKey key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersio ...

  7. Spring启动后获取所有拥有特定注解的Bean,注解的属性值

    最近项目中遇到一个业务场景,就是在Spring容器启动后获取所有的Bean中实现了一个特定接口的对象,第一个想到的是ApplicationContextAware,在setApplicationCon ...

  8. 杂项:WiKi

    ylbtech-杂项:WiKi Wiki是一种在网络上开放且可供多人协同创作的超文本系统,由沃德·坎宁安于1995年首先开发,这种超文本系统支持面向社群的协作式写作,同时也包括一组支持这种写作.沃德· ...

  9. Java-Maven-Runoob:Maven 项目模板

    ylbtech-Java-Maven-Runoob:Maven 项目模板 1.返回顶部 1. Maven 项目模板 Maven 使用 archetype(原型) 来创建自定义的项目结构,形成 Mave ...

  10. MariaDB 脚本

    研究MariaDB, 需要mock up一些假数据: 生成n个长度整型数的函数rand_num: CREATE DEFINER=`root`@`localhost` FUNCTION `rand_nu ...