WCF把書讀薄(4)——事務編程與可靠會話

  WCF把書讀薄(3)——數據契約、消息契約與錯誤契約html

 

  真不愧是老A的書,例子多,並且也講了很多原理方面的內容,不過越讀越以爲壓力山大……此次來稍微整理整理事務和可靠會話的內容。數據庫

  

  十8、事務編程編程

  WCF的分佈式事務編程,指的是在客戶端定義一個事務範圍,在這個範圍內對WCF服務進行連續調用,能夠實現其中一個出現問題總體回滾的效果。因爲WCF依賴於MSDTC,因此首先須要開啓MSDTC服務纔可以經過WCF進行分佈式事務編程。分佈式

  這裏我也本身寫了一個典型的銀行轉帳的練習,首先須要創建一個數據庫,數據表只有一張Account表,其中有AccountId和Money兩個int型字段,AccountId爲主鍵。裏面有兩個帳戶:帳戶1有1000,帳戶2有1000。ui

  首先,既然是分佈式事務,事務須要從客戶端流轉到服務端,那麼它們之間就應該達成「共識」,也就是說須要對服務契約作手腳。下面定義一個服務契約:spa

[ServiceContract(SessionMode = SessionMode.Required)]
public interface IBankService
{
    [OperationContract]
    [TransactionFlow(TransactionFlowOption.Mandatory)] void OutMoney(int fromAccountId, int money);

    [OperationContract]
    [TransactionFlow(TransactionFlowOption.Mandatory)]
    void InMoney(int toAccountId, int money);
}

  在轉帳的整個過程中,用戶首先發送一個OutMoney請求,減小帳戶1當中的錢,以後發送InMoney請求,增長帳戶2的錢。顯然這個契約須要一個會話,因此給服務契約增長SessionMode屬性。注意,在實際應用當中轉帳應該做爲一個完整的服務而不是兩個服務方法,這裏只是舉個例子而已。代理

  事務的流轉是一個操做行爲,因此須要在操做契約上增長TransactionFlow標記,並設置TransactionFlowOption的值,這個標記是事務的總開關。其值有三個:NotAllowed(默認值,客戶端事務禁止經過該方法流入服務端),Allowed(容許流入事務),Mandatory(必須在事務內調用),這裏將轉帳操做設置爲必須在事務內。code

  因爲事務操做必然伴隨着消息交換,因此OneWay操做必然是不支持事務的,即OneWay操做的TransactionFlowOption只能爲NotAllowed(下P143)!htm

  接下來實現這個服務操做,代碼以下,其中Repository細節就不貼了:blog

[ServiceBehavior(TransactionIsolationLevel = IsolationLevel.Serializable, TransactionTimeout = "00:05:00", TransactionAutoCompleteOnSessionClose = true)] public class BankService : IBankService
{
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)] public void OutMoney(int fromAccountId, int money)
    {
        try
        {
            AccountRepository repository = new AccountRepository();
            Account accOut = repository.GetAccountById(fromAccountId);
            accOut.Money -= money;
            repository.Save(accOut);
        }
        catch (Exception ex)
        {
            System.Transactions.Transaction.Current.Rollback(); throw new FaultException(new FaultReason(ex.Message));
        }
    }

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void InMoney(int toAccountId, int money)
    {
        try
        {
            AccountRepository repository = new AccountRepository();
            Account accIn = repository.GetAccountById(toAccountId);
            accIn.Money += money;
            repository.Save(accIn);
        }
        catch (Exception ex)
        {
            System.Transactions.Transaction.Current.Rollback();
            throw new FaultException(new FaultReason(ex.Message));
        }
    }
}

  服務操做的執行是否須要自動登記到事務當中,以及服務操做什麼時候提交,是服務端本身說了算的,因此要在具體的操做上設定操做行爲。這裏咱們用到兩個行爲:TransactionScopeRequired和TransactionAutoComplete,它們都是布爾值,前者用於決定操做是否歸入事務內,默認爲false,這裏須要設置爲true,後者用於決定該操做執行完畢後是否提交事務,因而在第一個操做上設置爲false,第二個操做設置爲true。

  在ServiceBehavior上能夠設定事務的行爲,

  最後須要在事務拋異常的狀況下回滾。TransactionIsolationLevel用於指定事務隔離級別,默認是Serializable,TransactionTimeout不解釋,TransactionAutoCompleteOnSessionClose表示在會話正常結束時是否自動提交事務,默認爲false,另外還有一個ReleaseServiceInstanceOnTransactionComplete,表示當事務完畢時是否須要釋放服務實例,默認爲false。

  寫完了服務端代碼就該改XML了,XML以下:

<configuration>
  <system.serviceModel>
    <bindings>
      <ws2007HttpBinding>
        <binding name="transactionalTcpBinding" transactionFlow="true" />
      </ws2007HttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="metadataBehavior">
          <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:9527/bankservice/metadata" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="Bank.Service.BankService" behaviorConfiguration="metadataBehavior" >
        <host>
          <baseAddresses>
            <add baseAddress="http://127.0.0.1:9527/"/>
          </baseAddresses>
        </host>
        <endpoint address="bankservice" binding="ws2007HttpBinding" bindingConfiguration="transactionalTcpBinding"
                  contract="Bank.Interface.IBankService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

  WCF是否有能力流轉事務以及事務按照怎樣的協議流轉,是綁定控制的。在WCF當中,除了BasicHttpBinding、NetMsmqBinding和MsmqIntegrationBinding外,都是支持事務傳播的(下P145),即使支持事務,事務流轉也是默認關閉的,因此須要配置綁定的transactionFlow屬性。這裏使用了ws2007HttpBinding,並將其transactionFlow屬性設置爲true。

  發佈服務後,在客戶端使用以下代碼調用服務:

static void Main(string[] args)
{
    BankServiceClient proxy = new BankServiceClient();
            
    using (TransactionScope transactionScope = new TransactionScope())
    {
        try
        {
            proxy.OutMoney(1, 100);
            proxy.InMoney(2, 100);
            transactionScope.Complete();
        }
        catch (Exception ex)
        {
            (proxy as ICommunicationObject).Abort();
        }
    }
}

  這裏定義了一個事務範圍,而且在最後提交了事務,若是出現異常,則關閉服務代理。這樣,在服務過程中若是出現了異常,事務就會回滾了。

 

  十9、可靠會話

  此次真的是名副其實地把書讀薄了!下冊書上全是原理,嗯,這裏不抄原理,只用來拷代碼,不過發現書上木有太多現成可用的代碼,因而就稍微總結總結好了。所謂可靠會話就是用於保證消息傳遞有效、有序、不重複的一套機制,WCF對這套機制的實現體如今一個叫ReliableSessionBindingElement的綁定元素上,因此要實現可靠會話,能夠修改綁定,或者手寫綁定。

  典型的應用就是文件分段傳輸,若是不實現可靠會話,分段傳輸就可能發生丟包、接收發送順序不一致和重複發送的問題。

  WCF已經爲咱們提供了不少支持可靠會話的內置綁定,其中wsHttpBinding、wsFederationBinding、netTcpBinding的可靠會話功能是默認關閉的,wsDualHttpBinding和netNamedPipesBinding是默認開啓的。

  啓動可靠會話很簡單,只要在綁定里加上配置:

<bindings>
  <netTcpBinding>
    <binding name="reliableNetTcpBinding">
      <reliableSession enabled="true"/>
    </binding>
  </netTcpBinding>
</bindings>

而且在終結點的bindingConfiguration屬性指定這個綁定配置就好了。須要注意客戶端和服務端的綁定配置要一致。  

  這個綁定配置節有幾個屬性,參考http://msdn.microsoft.com/zh-cn/library/ms731302.aspx,能夠用於作負載控制,不過不管如何,ordered要設置爲true才能開啓可靠會話(P255)。

  另外,若是咱們須要某個服務操做必需要保證有序性才能被執行,則須要在ServiceContract接口定義上多打上一個反射標籤:

[DeliveryRequirements(RequireOrderedDelivery = true)]

這樣一來,若是沒有在服務行爲上配置有序,則host時會報異常。

相關文章
相關標籤/搜索