0

Web Apiを呼び出す方法があります。データが複数のテーブルに挿入されるため、トランザクションが追加されます。以下はコードのレイアウトです。複数のメソッド呼び出しとネットワーク呼び出しにまたがるトランザクションを管理する

{ 

    TransactionObject objTransaction = new TransactionObject(); 
    try 
    { 

    //Create Order 
    order.insert(objTransaction); 

    //Create Delivery 
    address.insert(objTransaction); 

    //Call Generic Web API method to calculate TAX. 
    using (HttpClient client = new HttpClient()) 
     { 
      client.BaseAddress = new Uri("http://localhost:85766/"); 
      client.DefaultRequestHeaders.Accept.Clear(); 
      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
      var response = client.PostAsJsonAsync("api/Tax/UpdateTax", order).Result; 

      if (response.IsSuccessStatusCode) 
      {  
       //Commit transactio  
       objTransaction.EndTransaction(true);            
      } 
      else 
      { 
       //Commit transactio 
       objTransaction.EndTransaction(false); 
      } 

     } 
    } 
} 
catch(Exception ex) 
{ 
    //Commit transactio 
    objTransaction.EndTransaction(false); 
} 

このメソッドは、別のデータベース操作を実行するためにWeb APIを呼び出します。ウェブの下にあるApiは、フォームの複数の場所と呼ばれる一般的な方法です。

Web APIが呼び出される前に例外が発生すると、すべてのトランザクションがロールバックされます。それは結構です。 Web Apiで例外が発生した場合と同じです。

、それをどのように処理するか、mainメソッドでは、トランザクションをコミット中のWeb APIは、正常に実行されます後に例外が発生する場合は、私はコード

if (response.IsSuccessStatusCode) 
    {  
    //Commit transactio   
     objTransaction.EndTransaction(true);            
    } 

の下での意味は、ロジックを処理するために、任意のより良い方法はありますか?

+0

['TransactionScope'] (https://msdn.microsoft.com/en-us/library/system.transactions.transactionscope(v=vs.110).aspx)をアンビエントトランザクションオプションで使用します。 – kayess

+0

@kayess:大域トランザクションオプションは、ネットワーク通話では機能しません。私は、ネットワーク上でトランザクションidを流す答えを掲示しました。お持ちの場合は、フィードバックをお願いします。 –

答えて

1

現在の実装では、UpdateTaxメソッドが終了した後にエラーが発生した場合(ネットワークの問題など)を考慮して、データが保存されていてもエラーを受け取ります。

TransactionScopeを使用して分散トランザクションを作成することで、改善することができます。

分散トランザクションを機能させるには、Distributed Transaction Coordinator(DTC)を有効にする必要があります。https://msdn.microsoft.com/en-us/library/dd327979.aspx。私はあなたのウェブAPIアプリケーションがメインアプリケーションの同じドメインネットワークにあるとも仮定します。

あなたのケースでは、彼のコメントに@kayessが示唆しているように、アプリケーション境界内のメソッド呼び出しを介してトランザクションを流すためのアンビエントトランザクションを作成できます。しかし、アンビエントトランザクションはネットワークコールでは機能しません。そのためには追加のロジックを実装する必要があります。

フローあなたのウェブアプリケーションとのトランザクションIDはあなたのメインアプリケーションと同じトランザクションに参加することができます。

using (var scope = new TransactionScope()) //create ambient transaction by default. 
    { 
     //Create Order (insert Order using your local method) 

     //Create Delivery (insert Delivery using your local method) 

     using (var client = new HttpClient()) 
     { 
      client.BaseAddress = new Uri("http://localhost:85766/"); 
      client.DefaultRequestHeaders.Accept.Clear(); 
      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
      //Send current transaction id as header in the http request 
      var token = TransactionInterop.GetTransmitterPropagationToken(Transaction.Current); 
      //You could improve it by creating a HttpRequestMessage, here is just to demonstrate the idea. 
      client.DefaultRequestHeaders.Add("TransactionToken", Convert.ToBase64String(token));  

      var response = client.PostAsJsonAsync("api/Tax/UpdateTax", order).Result; 
      //Do some more stuff 
      .. 

      //If there is no exception and no error from the response 
      if (response.IsSuccessStatusCode) { 
       scope.Complete(); //Calling this let the transaction manager commit the transaction, without this call, the transaction is rolled back   
      } 
     } 
    } 

ウェブAPIメソッド:

[HttpPost] 
    public HttpResponseMessage UpdateTax(Order order) 
    {    
     try 
     { 
      //Retrieve the transaction id in the header 
      var values = Request.Headers.GetValues("TransactionToken"); 
      if (values != null && values.Any()) 
      { 
       byte[] transactionToken = Convert.FromBase64String(values.FirstOrDefault()); 
       var transaction = TransactionInterop.GetTransactionFromTransmitterPropagationToken(transactionToken); 
       //Enlist in the same transaction 
       using(var transactionScope = new TransactionScope(transaction) 
       { 
        //DO calculation logic 
        . 
        . 
        //Insert Invoice 

        transactionScope.Complete(); 
       } 
      } 
      return Request.CreateResponse(HttpStatusCode.Created, "Invoice data added successfully"); 
     } 
     catch (Exception ex) 
     { 
      return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Erorr while adding invoice"); 
     } 

    } 

これで動作するようにコードを調整するために助けてください以下は、メインアプリケーションのコード例です。私はちょうどアイデアを示しています(nullチェック、TransactionScopeで動作する古いデータベースメソッドを調整しない、コード再利用性を高めるためにActionMethodに抽出する...)

関連する問題