[转]WCF分布式事务
WCF 支持分布式事务,也就是说事务可以跨越服务、进程、机器边界,在多个服务和客户端间存在。
Single service/single resource transaction
Distributed transactional service-oriented application
Transaction Binding
只有 TCP-、 IPC- 以及 WS-related 等 Binding 支持事务。缺省情况下,这些 Binding 并不会参与事务,需要我们显示将 TransactionFlow 属性设置为 true 才行。
WCF 使用不同的事务管理协议来控制事务执行范围(execution scope)。
Transaction modes
我们可以将事务分为三种类型,分别是 Client/Service transaction、Client transaction、Service transaction。
1. Client/Service transaction,最常见的一种事务模型,通常由客户端或服务本身启用一个事务。
设置步骤:
(1) 选择一个支持事务的Binding,设置 TransactionFlow = true。
(2) 设置 TransactionFlow(TransactionFlowOption.Allowed)。
(3) 设置 OperationBehavior(TransactionScopeRequired=true)。
2. Client transaction,强制服务必须参与事务,而且必须是客户端启用事务。
设置步骤:
(1) 选择一个支持事务的Binding,设置 TransactionFlow = true。
(2) 设置 TransactionFlow(TransactionFlowOption.Mandatory)。
(3) 设置 OperationBehavior(TransactionScopeRequired=true)。
3. Service transaction,服务必须启用一个根事务,且不参与任何外部事务。
设置步骤:
(1) 选择任何一种Binding,设置 TransactionFlow = false(默认)。
(2) 设置 TransactionFlow(TransactionFlowOption.NotAllowed)。
(3) 设置 OperationBehavior(TransactionScopeRequired=true)。
Single service/single resource transaction
Distributed transactional service-oriented application
Transaction Binding
只有 TCP-、 IPC- 以及 WS-related 等 Binding 支持事务。缺省情况下,这些 Binding 并不会参与事务,需要我们显示将 TransactionFlow 属性设置为 true 才行。
NetTcpBinding tcpBinding = new NetTcpBinding( );
tcpBinding.TransactionFlow = true;
tcpBinding.TransactionFlow = true;
或
<bindings>
<netTcpBinding>
<binding name = "TransactionalTCP" transactionFlow = "true" />
</netTcpBinding>
</bindings>
<netTcpBinding>
<binding name = "TransactionalTCP" transactionFlow = "true" />
</netTcpBinding>
</bindings>
TransactionFlow 并不会在 Metadata 中发布,也就是说我们同样需要手动设置客户端 Binding 的 TransactionFlow 属性。
代码
WSHttpBinding binding = new WSHttpBinding();
binding.TransactionFlow = true;
ChannelFactory<IContract> factory = new ChannelFactory<IContract>(binding, "http://localhost:8080/myservice");
IContract client = factory.CreateChannel();
using (client as IDisposable)
{
using (TransactionScope scope = new TransactionScope())
{
client.Test();
scope.Complete();
}
}
binding.TransactionFlow = true;
ChannelFactory<IContract> factory = new ChannelFactory<IContract>(binding, "http://localhost:8080/myservice");
IContract client = factory.CreateChannel();
using (client as IDisposable)
{
using (TransactionScope scope = new TransactionScope())
{
client.Test();
scope.Complete();
}
}
启用可靠性(Reliability)通讯有助于减少事务失败的可能性,如果使用 NetTcpBinding、WSHttpBinding,建议做如下设置,以便启用可靠性传输。而 NetNamedPipeBinding 和 WSDualHttpBinding 默认就是可靠性,则无需再做调整。
NetTcpBinding binding = new NetTcpBinding();
binding.ReliableSession.Enabled = true;
binding.ReliableSession.Enabled = true;
Transaction Protocols
WCF 使用不同的事务管理协议来控制事务执行范围(execution scope)。
- Lightweight: 仅能在同一程序域的上下文中传递事务,无法跨越程序域和服务边界。只能在服务内部或外部适用,同时它也是性能最好的一种协议。不过这种协议似乎没什么用处,因为 WCF Framework 中没有任何一种 Binding 支持此协议。
- OleTx: 允许事务跨越程序域、进程或机器边界。使用 RPC 调用,采取 Windows 专用二进制格式。无法跨越防火墙,也不能和其他异种平台进行整合。多用于 Windows 体系的 Intranet 环境。
- WS-Atomic(WSAT): 和 OleTx 相似,同样允许事务跨越程序域、进程或机器边界。和 OleTx 不同,WSAT 是一种工业标准,采取 HTTP 协议,TEXT 编码,可以跨越防火墙。虽然 WSAT 也能用于 Intranet,但多数时候它用于 Internet 环境。
NetTcpBinding tcpBinding = new NetTcpBinding( );
tcpBinding.TransactionFlow = true;
tcpBinding.TransactionProtocol = TransactionProtocol.WSAtomicTransactionOctober2004;
tcpBinding.TransactionFlow = true;
tcpBinding.TransactionProtocol = TransactionProtocol.WSAtomicTransactionOctober2004;
或
代码
<bindings>
<netTcpBinding>
<binding name = "TransactionalTCP"
transactionFlow = "true"
transactionProtocol = "WSAtomicTransactionOctober2004"
/>
</netTcpBinding>
</bindings>
<netTcpBinding>
<binding name = "TransactionalTCP"
transactionFlow = "true"
transactionProtocol = "WSAtomicTransactionOctober2004"
/>
</netTcpBinding>
</bindings>
Transactional Service
除了开启 Binding 的事务支持外,我们还必须通过 TransactionFlow 和 TransactionScopeRequired 来控制服务是否参与和使用事务。
TransactionFlowAttribute 只能用于服务方法(Operation/Method)上,它允许我们进行不同的事务参与设置。有一点要注意,我们不能为 IsOneWay=true 的服务设置事务支持。
- TransactionFlowOption.NotAllowed: 不参与任何事务。(默认值)
- TransactionFlowOption.Allowed: 允许参与事务。也就是说,如果调用方(客户端)和服务Binding启用了事务,则参与。
- TransactionFlowOption.Mandatory: 强制启用事务。调用方(客户端)和服务 Binding 必须启用事务才能调用本服务。
代码
[ServiceContract]
public interface IService
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void Test();
}
public class Service : IService
{
[OperationBehavior(TransactionScopeRequired=true)]
public void Test()
{
Transaction transaction = Transaction.Current;
Debug.Assert(transaction == null);
}
}
public interface IService
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void Test();
}
public class Service : IService
{
[OperationBehavior(TransactionScopeRequired=true)]
public void Test()
{
Transaction transaction = Transaction.Current;
Debug.Assert(transaction == null);
}
}
Transaction modes
我们可以将事务分为三种类型,分别是 Client/Service transaction、Client transaction、Service transaction。
1. Client/Service transaction,最常见的一种事务模型,通常由客户端或服务本身启用一个事务。
设置步骤:
(1) 选择一个支持事务的Binding,设置 TransactionFlow = true。
(2) 设置 TransactionFlow(TransactionFlowOption.Allowed)。
(3) 设置 OperationBehavior(TransactionScopeRequired=true)。
2. Client transaction,强制服务必须参与事务,而且必须是客户端启用事务。
设置步骤:
(1) 选择一个支持事务的Binding,设置 TransactionFlow = true。
(2) 设置 TransactionFlow(TransactionFlowOption.Mandatory)。
(3) 设置 OperationBehavior(TransactionScopeRequired=true)。
3. Service transaction,服务必须启用一个根事务,且不参与任何外部事务。
设置步骤:
(1) 选择任何一种Binding,设置 TransactionFlow = false(默认)。
(2) 设置 TransactionFlow(TransactionFlowOption.NotAllowed)。
(3) 设置 OperationBehavior(TransactionScopeRequired=true)。