1. 程式人生 > >WCF(三)分布式事務

WCF(三)分布式事務

star valid core use row false eight cto metadata

最近在學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(三)分布式事務