最近在學WCF,所以有兩個設想疑問(菜鳥多疑問):
- 如果有WCF服務A,WCF服務B,客戶端調用WCF服務A插入一條數據,然后再調用服務B也插入一條數據,然而服務B出錯了進行了回滾,服務A能不能也進行回滾操作?
- 或是客戶端調用服務A和服務B,成功了插入了兩條數據之后,客戶端這邊出錯了,如何讓服務A和服務B插入的數據也回滾操作?
經過學習探索,了解到WCF支持分布式事務,事務可以在多個服務中傳播,也可以在服務端與客戶端之間傳播。
注:WCF內並非所有綁定都支持事務的,常用的BasicHttpBinding就不支持事務的傳播。只有以下幾個綁定才能支持事務流的運轉:NetTcpBinding、WSHttpBinding、WSDualHttpBinding、WSFederationHttpBinding、NetNamedPipeBinding。
代碼嘗試
先建一個WCF服務(WSHttpBinding),有兩個Add方法,在客戶端兩次分開調用
[ServiceContract] public interface IService1 { [OperationContract] string AddData_1(string a); [OperationContract] string AddData_2(string a); }
public class Service1 : IService1 { [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] [TransactionFlow(TransactionFlowOption.Allowed)] public string AddData_1(string b) { using (testEntities ts = new testEntities()) { Student a = new Student() { Age = 9999999, Class = b, Sex = "男", Score = 100 }; ts.Student.Add(a); ts.SaveChanges(); } return "22222"; } [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] [TransactionFlow(TransactionFlowOption.Allowed)] public string AddData_2(string b) { using (testEntities ts = new testEntities()) { Student a = new Student() { Age = 9999999, Class = b, Sex = "男", Score = 100 }; ts.Student.Add(a); ts.SaveChanges(); throw new Exception("出錯拉!"); //拋出錯誤 } return "22222"; } }
其中標紅解釋:
TransactionScopeRequired:值為true時,表示此WCF服務的方法中啟動事務,為false,反之不啟動。
TransactionAutoComplete:值為true時為隱式事務,方法在運行過程中沒有拋出Exception,事務會自動提交。如果期間出現任何異常,事務就會自動回滾;false時,顯式事務,必須OperationContext.Current.SetTransactionComplete () 顯式提交事務。
TransactionFlowOption:設置為Allowed,開啟事務傳播,客戶端的事務傳播到服務端。
有三個值:
NotAllowed,禁止客戶端傳播事務流到服務端,即使客戶端啟動了事務,該事務也會被忽略;
Allowed,允許客戶端的事務傳播到服務端,但服務器端不一定會引用到此事務(如果服務端方法沒開啟事務);
Mandatory,服務端與客戶端必須同時啟動事務流,否則就會拋出InvalidOperationException異常。
web.config配置(重要)
服務端web.config
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<!--啟動事務流--> <binding name="defaultWSHttpBinding" transactionFlow="true" /> <!--這里一定要設置綁定的transactionFlow為true,否則無法使用事務-->
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 為避免泄漏元數據信息,請在部署前將以下值設置為 false -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<!-- 要接收故障異常詳細信息以進行調試,請將以下值設置為 true。在部署前設置為 false 以避免泄漏異常信息 -->
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="WcfDemo_shiwu.Service1">
<endpoint address="" binding="wsHttpBinding"
contract="WcfDemo_shiwu.IService1" bindingConfiguration="defaultWSHttpBinding"/> <!--這里一定要設置bindingConfiguration-->
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<!--
若要在調試過程中瀏覽 Web 應用程序根目錄,請將下面的值設置為 True。
在部署之前將該值設置為 False 可避免泄露 Web 應用程序文件夾信息。
-->
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>
客戶端
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1" transactionFlow="true" />
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:5854/Service1.svc" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService1" contract="TestService.IService1"
name="WSHttpBinding_IService1">
<identity>
<userPrincipalName value="DESKTOP-350R9O7\qiuguochao" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
客戶端代碼
情況一:WCF服務中的方法2報錯回滾,那么之前第一次調用插入的是否成功回滾?
static void Main(string[] args) { //客戶端開啟分布式事務,要引用System.Transactions.dll using (TransactionScope ts = new TransactionScope()) { //調用服務 using (TestService.Service1Client service = new TestService.Service1Client()) { service.AddData_1("1"); }
Console.WriteLine("第一次調用:成功插入一條數據");
//重新去調用WCF服務 using (TestService.Service1Client service2 = new TestService.Service1Client()) { //WCF中的AddData_2會報錯 service2.AddData_2("2"); } ts.Complete(); } }
結果:

WCF服務插入第二條數據,已經報錯,因為該方法中已經設置 [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)],開啟了事務,所以第二數據肯定是會被回滾的
且看第一條數據是否也會被回滾?,結果是兩條數據都被回滾了

情況2:兩次調用WCF服務成功插入數據后,客戶端報錯回滾,在WCF服務中插入的數據是否也回滾?
將拋出錯誤注釋掉,重新運行WCF服務

改寫客戶端代碼,並設下斷點:

執行到斷點,查看數據情況

已經成功插入,繼續執行,由於沒有進行提交,所以該事務將會自動回滾,且看在WCF服務中插入的數據是否會被回滾

客戶端進行了回滾操作,很顯然,客戶端的事務傳播的WCF中的方法事務,也將相應的操作回滾。
