【发布时间】:2018-05-22 03:58:11
【问题描述】:
当我使用两个不同的服务来更新两个不同的数据库——一个是 SQL 数据,另一个是 Couchbase 数据时,如何使用 WCF 服务实现回滚数据库更新?
代码如下:
My web.config looks like this:
Web.Config:
<system.serviceModel>
<diagnostics>
<messageLogging logMalformedMessages="true" logMessagesAtTransportLevel="true" />
</diagnostics>
<behaviors>
<serviceBehaviors>
<behavior name="TransactionBehavior">
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<!--<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />-->
<serviceMetadata httpGetEnabled="True" />
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="ImpersonationBehavior">
<clientCredentials>
<windows allowedImpersonationLevel="Impersonation" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="wsHttpTransactionBinding" receiveTimeout="00:20:00" sendTimeout="00:20:00" bypassProxyOnLocal="false" transactionFlow="true" maxReceivedMessageSize="2147483647" messageEncoding="Mtom">
<!--<reliableSession enabled="false" />-->
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="TransactionBehavior" name="BankingService.AccountService">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpTransactionBinding" name="wsHttpEndPoint" contract="SharedLib.IAccountService" />
</service>
</services>
<!--Fix could not activate service error-->
<serviceHostingEnvironment minFreeMemoryPercentageToActivateService="1" multipleSiteBindingsEnabled="true">
<!--<serviceHostingEnvironment>-->
<serviceActivations>
<add relativeAddress="AccountService.svc" service="BankingService.AccountService" factory="WebApp.UnityServiceHostFactory, WebApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</serviceActivations>
</serviceHostingEnvironment>
<client>
<endpoint address="http://localhost:9003/AccountService.svc" behaviorConfiguration="ImpersonationBehavior" binding="wsHttpBinding" bindingConfiguration="wsHttpTransactionBinding" contract="SharedLib.IAccountService" name="wsHttpEndPoint" kind="" endpointConfiguration="" />
</client>
</system.serviceModel>
App.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpTransactionBinding" transactionFlow="true" openTimeout="00:10:00" useDefaultWebProxy="true" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" receiveTimeout="00:20:00" sendTimeout="00:20:00" maxReceivedMessageSize="2147483647" messageEncoding="Mtom">
<security mode="None">
</security>
</binding>
</wsHttpBinding>
<netTcpBinding>
<binding name="netTcpTransactionBinding" transactionFlow="true" sendTimeout="00:20:00" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ImpersonationBehavior">
<clientCredentials>
<windows allowedImpersonationLevel="Impersonation" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://localhost:9003/AccountService.svc"
behaviorConfiguration="ImpersonationBehavior" binding="wsHttpBinding"
bindingConfiguration="wsHttpTransactionBinding" contract="SharedLib.IAccountService"
name="wsHttpEndPoint" kind="" endpointConfiguration="" />
</client>
</system.serviceModel>
ServiceContract is as below:
IAccountService.cs
[ServiceContract]
public interface IAccountService
{
[OperationContract]
Task<IEnumerable<Account>> GetAccounts();
[OperationContract, TransactionFlow(TransactionFlowOption.Allowed)]
Task<bool> Debit(int accountID, int amount);
[OperationContract, TransactionFlow(TransactionFlowOption.Allowed)]
Task<bool> Credit(int accountID, int amount);
[OperationContract]
Task<int> GetBalance(int accountID);
[OperationContract]
Task<MiniStatement> GetMiniStatement(int accountID);
}
Service Implementation is as below:
Account.cs
[ServiceBehavior(
TransactionIsolationLevel =
System.Transactions.IsolationLevel.ReadCommitted,ConcurrencyMode = ConcurrencyMode.Multiple, ReleaseServiceInstanceOnTransactionComplete = false)]
public class AccountService : IAccountService
{
BankRepository bankRepository = new BankRepository();
CouchbaseRepository couchbaseRepository = new CouchbaseRepository();
public AccountService()
{
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public Task<bool> Credit(int accountID, int amount)
{
var creditAccountTask = Task.Run(async () =>
{
return await bankRepository.CreditAccount(accountID, amount, Transaction.Current);
});
var result = creditAccountTask.ContinueWith(async (t) =>
{
return t.Result != null ? await couchbaseRepository.CreditAccount(accountID, t.Result) : false;
}, TaskContinuationOptions.OnlyOnRanToCompletion);
return result.Result;
}
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public Task<bool> Debit(int accountID, int amount)
{
var debitAccountTask = Task.Run(async () =>
{
return await bankRepository.DebitAccount(accountID, amount, Transaction.Current);
});
var result = debitAccountTask.ContinueWith(async (t) =>
{
return t.Result != null ? await couchbaseRepository.DebitAccount(accountID, t.Result) : false;
}, TaskContinuationOptions.OnlyOnRanToCompletion);
return result.Result;
}
public Task<IEnumerable<Account>> GetAccounts()
{
return bankRepository.GetAccounts();
}
public Task<int> GetBalance(int accountID)
{
return bankRepository.GetBalanceByAccountID(accountID);
}
public Task<MiniStatement> GetMiniStatement(int accountID)
{
return couchbaseRepository.GetTransactionStatement(accountID);
}
}
当我使用 EF 保存更改时,事务仍然不起作用。 Transaction.Current 仍然为 null。
【问题讨论】:
-
你需要一个分布式事务协调器
-
我用过。相关问题是我在哪里启用 MSDTC?我有一个客户端,服务托管在另一个盒子中,SQL 服务器和 couchbase 数据库托管在不同的服务器中。我绝对不能在客户端机器上启用 MSDTC,因为我们的是桌面应用程序并且我们使用 ClickOnce 部署。
标签: sql wcf transactions couchbase rollback