WCF(三)分布式事務
最近在學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中的方法事務,也將相應的操作回滾。
WCF(三)分布式事務