65.9K
CodeProject 正在变化。 阅读更多。
Home

WCF 事务 - 简要介绍

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.64/5 (18投票s)

2011 年 4 月 20 日

CPOL

8分钟阅读

viewsIcon

89360

downloadIcon

1988

关于 WCF 事务的初步信息

引言

我相信事务对你来说不是一个新概念,但你想了解 WCF 如何实现它。这篇简短的文章触及了 WCF 事务的一些边缘概念。它适用于对 WCF 有一定了解并想开始了解该概念的人。它提供了一些关于事物工作原理的基本想法,并为进一步阅读奠定了基础。事务是一个庞大的概念,无法在一篇文章中解释清楚。

Using the Code

在继续阅读之前,最好下载附件中的代码并在您的计算机上进行配置。文章会修改代码并解释其效果,因此边阅读边实践会更具说明性。

解释

什么是事务?

虽然我们理解,但还是重申一下——事务意味着一组符合 ACID 原则的操作。

  • 原子性 (Atomic) - 要么所有操作都对系统产生影响,要么都不产生。
  • 一致性 (Consistency) – 无论操作集如何,系统始终处于一致状态。
  • 隔离性 (Isolation) – 系统的中间状态不会暴露给外部世界。
  • 持久性 (Durability) – 系统的状态将被持久化,不会易失。

一般来说,在 WCF 中通常会遇到两种事务——一种是客户端发起某个事务,执行一些工作,然后将其传播到服务器以在其中完成一些工作;另一种是客户端不发起任何事务,但要求服务器在某个事务中执行某个操作。

当事务不跨越其 Appdomain 的边界时,它是本地事务,否则可以视为分布式事务。WCF 提供了强大的支持来处理这些事务,我们将在稍后介绍。

事务是一个很大的话题,无法在这篇短文中涵盖,但它将提供一个关于如何开始使用它的简要介绍。

如何在 WCF 中配置事务?

当我们分析某些逻辑足够关键,值得用事务包装(例如账户的贷记-借记)时,首先应确定逻辑的哪个部分——服务端、客户端还是两者都需要事务。事务可能只需要在服务内部,或者可能在客户端发起然后传播到服务,或者可能仅在客户端。这个决定在实际配置事务时会很有帮助。

在 WCF 中配置事务时需要考虑一些因素:

绑定 (Binding) - WCF 中只有少数绑定支持事务,它们是 NetTcpBindingNetNamedPipeBindingWSHttpBindingWSDualHttpBindingWSFederationHttpBinding。因此,为了配置事务,必须从这些绑定中选择一个。尽管这些绑定支持事务,但默认情况下它是禁用的,因此需要手动启用它们。

操作契约和行为 (Operation Contract and behavior) - 合适的绑定仅仅为事务从客户端到服务的传播提供了途径,但在服务端,只有一个操作/方法将负责处理事务。因此,下一步是配置操作。操作通常使用以下两个属性进行配置:

A) TransactionFlow – 此属性设置为一个名为 TransactionFlowOption 的参数,该参数有三个值。这些值不言自明:

  1. Allowed – 表示如果客户端有事务,则接受;否则不构成问题。
  2. NotAllowed – 客户端在调用方法时不能向服务器发送事务。
  3. Mandatory – 客户端必须创建一个事务,否则无法调用该方法。

B) TransactionScopeRequired -OperationBehavior 描述了方法/操作是否应在事务中执行其工作。

现在我们将它们放在一起。有一些逻辑应该放在某个事务中。WCF 有一些支持事务的绑定,但默认情况下是禁用的。要启用事务从客户端到服务的流,应启用绑定支持。在绑定支持就绪后,通过设置 TransactionFlow 属性来配置方法以接受来自客户端的事务。最后,配置 TransactionScopeRequired ,以便服务方法可以在事务中运行。

让我们进行不同的配置,看看会发生什么。

在深入实验之前,我先告诉你,在附件的示例中,我们有一个简单的服务,其配置最少,使其能够正常工作,一个带有按钮点击事件的客户端 WinForm 应用程序,以及一个简单的数据库 emp 表。现在我们将进行一些实验,看看当我们执行某些操作时会发生什么。

  1. 第一次尝试时,我们将只用 TransactionScopeRequired = false 来修饰 upload 方法。代码将如下所示:
[OperationBehavior (TransactionScopeRequired=false)]
public void upload()
{
   // some code...
} 

现在运行应用程序(按 Ctrl + F5 以发布模式运行),尽管您会看到一些错误,但 Emp 表中仍会获得一些数据。Emp 表获得数据是因为该方法不在某个事务中。这次,只需将此属性设置为 true ,看看会发生什么。您的代码将如下所示:

[OperationBehavior(TransactionScopeRequired=true)]
public void upload()
{      
   // Some code...  
}

这次,数据库不会获得新条目。这是因为该方法在某个事务下运行,而该事务仅在代码执行没有错误时才提交。这里,我们只是用“TransactionScopeRequired”属性修饰了该方法,WCF 会处理其余的事情。如果 WCF 在执行过程中未发现任何异常,它会提交事务,而不会在意其他任何事情。我们可以通过另一个属性“TransactionAutoComplete”来控制此默认行为。默认情况下,其值为 true ,但如果指定为 false,即使代码中没有异常,WCF 也不会提交事务,然后您需要自己提交。

只需让您的代码看起来像这样:

[OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=false )]    
public void upload()
{
   // some code…
}

您必须按照如下所示使用以下属性来修饰您的服务合同。这是因为 TransactionAutoComplete=false 仅适用于有会话的调用。

[ServiceContract(SessionMode = SessionMode.Required)]  
public interface Iservice
{
   //some code…
}  

只需注释掉在服务方法中引发异常的行并运行代码。尽管您不会收到任何异常,但数据库仍未获得新条目。这是因为 WCF 没有按默认方式工作,而是由您来提交事务。现在,在您刚刚注释掉的行之后,写入以下内容以显式提交事务:

OperationContext.Current.SetTransactionComplete();

运行代码,这次您的数据库将获得新条目。这是因为您正在显式地提交事务。

我们来总结一下。到目前为止,我们已经通过使用名为 TransactionScopeRequired TransactionAutoComplete 的两个属性来处理方法。TransactionScopeRequired 指定方法是否将在某个事务中执行,而另一个属性 TransactionAutoComplete 指定 WCF 是否可以在没有错误的情况下提交事务,或者是否需要程序员来提交事务。

在下一节中,我们将从客户端传播事务到服务。

之前,我们观察到,如果配置了“TransactionScoperequired”,服务中的方法将在某个事务下运行,并且该事务是在服务方法本身中创建的。到目前为止一切顺利,但如果客户端有一些代码与服务协同工作,并期望作为一个整体提交(客户端逻辑 + 服务器逻辑),该怎么办?在这种情况下,客户端将需要一个事务,客户端将在该事务下完成其工作,然后将其传递给服务,服务将在其中完成其工作,并且只有在一切正常的情况下,才会由客户端提交。为了使事务从客户端流向服务,需要进行一些配置。

  1. 绑定配置 – 因为 WCF 中只有少数绑定支持事务流。
  2. 操作行为 - 我们需要告诉操作/方法如何响应事务。

让我们看看如何使用它。再次解压新的代码,或者撤销所有已做的更改,然后打开服务的配置文件,并在 endpoint 中添加 bindingConfiguration="newbinding",并相应地指定绑定配置。

<bindings>
 <wsHttpBinding>
   <binding name="newbinding" transactionFlow ="True" />
 </wsHttpBinding>    
</bindings>

由于我们已经有了支持事务的绑定,因此无需更改绑定。通过 TransactionFlow 属性启用操作契约以接受客户端的事务,如下所示:

[ServiceContract]
public interface Iservice
{
   [OperationContract]
   [TransactionFlow(TransactionFlowOption.Allowed)]
   void upload();
} 

确保服务方法已用 TransactionScopeRequired 修饰,如下所示:

[OperationBehavior(TransactionScopeRequired = true)]
public void upload()
{
   // some code...            
}

生成新的代理,并使用较新的服务类和 app.config 更新客户端。

在客户端,添加对 System.Transaction 的引用,并将按钮点击事件处理程序修改为如下所示:

try
{
  using(TransactionScope scope = new TransactionScope())
  {
     IserviceClient client = new IserviceClient();
     client.upload();
     client.upload();

     scope.Complete();
     MessageBox.Show("All is well!!!");
  }
}
catch
{
   MessageBox.Show("Some error occurred...");      
} 

请注意代码,我们已将逻辑用 Transaction scope 包围起来。此事务范围会流向服务,然后在服务中,代码在该事务下运行。这里的 scope.complete() 负责提交事务。如果删除此行,事务将不会被提交,数据库也不会保留任何更改。

如果您交换上面代码中的第二个 client.upload() scope.complete() ,那么第二个服务调用将无效。同样,您可以尝试 TransactionFlowTransactionScopeRequiredTransactionAutoComplete 等属性的不同组合,以学习更多内容。

暂时就这些。让我们快速回顾一下。

  • 在 WCF 中,只有少数绑定支持事务。
  • 默认情况下,这些绑定的事务流是禁用的。
  • TransactionFlow TransactionScopeRequired 属性是配置服务操作/方法所必需的。
  • WCF 的自动提交行为可以通过 TransactionAutoComplete 属性进行控制。

希望这篇小文章能让您对 WCF 事务有所了解,现在您将能够自行进行实验。我建议您查阅 MSDN 以深入分析该概念。

尽管我已尽力确保内容无误,但如果有什么遗漏或需要更正的地方,请告诉我,这将对我们所有人都有帮助。

祝您进一步阅读一切顺利。

编程愉快。

© . All rights reserved.