2016-12-25 67 views
2

我有一個更新方法,獲取最後一個活動項目,並用新值克隆它,並將活動標誌設置爲true。我的問題是更新方法是由多個Web API方法調用的,所以最後一個活動項目並不總是相同的。我結束了多個活動項目和數據不一致。所以我想鏈接所有電話,以解決這個問題,但我不知道在哪裏start.`在c#中鏈接多個相同的方法調用#

[HttpPost] 
[Route("Route2")] 
[ValidateModel] 
public async Task<HttpResponseMessage> Post(string contractReference, [FromBody] Family input) 
{ 
    return await CallPartialUpdate(contractReference, p => p.Family = input); 
} 


[HttpPost] 
[Route("Route3")] 
[ValidateModel] 
public async Task<HttpResponseMessage> Post(string contractReference, [FromBody] Address input) 
{ 
    return await CallPartialUpdate(contractReference, p => p.Address = input); 
} 



private async Task<HttpResponseMessage> CallPartialUpdate(string reference, Item itemToUpdate) 
{ 
    try 
    { 
     var existingItem = _bContext.RetrieveLastActive(reference); 

     if (existingItem == null) 
      return Request.CreateResponse(HttpStatusCode.NotFound); 

     var newRecord = existingItem.Document.Clone(); 

     newRecord.update(itemToUpdate); 
     newRecord.active = true; 

     await _bContext.PutDocumentAsync(newRecord, reference); 

     return Request.CreateResponse(HttpStatusCode.Created); 
    } 
    catch (System.Exception exception) 
    { 
     return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, exception.Message); 
    } 
}` 

基於@Asti答案我創建單元測試與觀察到的Rx但我仍然有數據矛盾中的最後一項,所以我如何得到這個工作,我如何獲得callPartialUpdate()的結果,謝謝

[TestFixture] 
public class Concurrency 
{ 

    [Test] 
    public async Task Update_Should_Always_Change_Last_Item() 
    { 
     var observer = Observable.Timer(TimeSpan.FromMilliseconds(1)); 
     var items = new List<Item>() 
     { 
      new Item() { FirstName = "AA", LastName = "BB" , IsActive = true }, 
      new Item() { FirstName = "A", LastName = "A" , IsActive = false }, 
     }; 
     await Task.Run(() => 
     { 
      Parallel.Invoke(async() => await observer.Select(item => Observable.FromAsync(ct => UpdateItem(items, new Item() { FirstName = "AAA" }))) 
          .Concat(), 
          async() => await observer.Select(item => Observable.FromAsync(ct => UpdateItem(items, new Item() { LastName = "BBB" }))) 
          .Concat()); 
     }); 
     var lastItem = items.Single(w => w.IsActive); 
     Assert.AreEqual("AAA", lastItem.FirstName); 
     Assert.AreEqual("BBB", lastItem.LastName); 
    } 


    public async Task<bool> UpdateItem(List<Item> items, Item itemToUpdate) 
    { 
     return await Task.Run(() => update(items, itemToUpdate)); 
    } 

    private bool update(List<Item> items, Item itemToUpdate) 
    { 
     var lastItem = items.Single(w => w.IsActive == true); 
     lastItem.IsActive = false; 
     var newItem = new Item() 
     { 
      FirstName = string.IsNullOrEmpty(itemToUpdate.FirstName) ? lastItem.FirstName : itemToUpdate.FirstName, 
      LastName = string.IsNullOrEmpty(itemToUpdate.LastName) ? lastItem.LastName : itemToUpdate.LastName, 
      IsActive = true 
     }; 

     items.Add(newItem); 
     return true; 
    } 
} 
+2

您需要一個鎖 - 如果我們能夠看到您的代碼,它會更容易幫助。 – Hogan

+0

@霍根,感謝您的評論,但與鎖會產生死鎖我想在更新行動中使用被動擴展訂閱,但我不知道如何實現它 – moyomeh

+0

鎖只會生成一個死鎖,如果你做錯了。如果你做得對,它會解決你的問題。 – Hogan

回答

1

對於更新的序列,這是枚舉或觀察到的:

 updates 
      .Select(item => Observable.FromAsync(ct => CallPartialUpdate(item))) 
      .Concat(); 

如果你想瞄準基於的Rx API,然後

  • 有方法調用返回觀測
  • 等待觀測,而不是任務
  • 注意在專用調度工作,以部分順序單位
+0

謝謝你的回答我用一些單元測試更新我的問題,所以我如何讓web api調用訂閱obsevable,以及如何獲得每個CallPartialUpdate()的返回結果 – moyomeh

+0

應用上述運算符後,您將獲得一個序列產生值 - 這個值是CallPartialUpdate的結果。 – Asti

0

添加

public class Concurrency 
{ 
    private Object thisLock = new Object(); 

然後

private bool update(List<Item> items, Item itemToUpdate) 
    { 
    lock (thisLock) 
    { 
     var lastItem = items.Single(w => w.IsActive == true); 
     lastItem.IsActive = false; 
     var newItem = new Item() 
     { 
     FirstName = string.IsNullOrEmpty(itemToUpdate.FirstName) ? lastItem.FirstName : itemToUpdate.FirstName, 
     LastName = string.IsNullOrEmpty(itemToUpdate.LastName) ? lastItem.LastName : itemToUpdate.LastName, 
     IsActive = true 
     }; 

     items.Add(newItem); 
    } 
    return true; 
    } 

在任何給定的時間,鎖中的區域只會由一個線程運行,並且將按預期運行。

對於您不得不以其他方式進行排序的順序不能保證 - 以何種方式取決於您要執行的規則。