2016-12-25 3 views
2

У меня есть метод обновления, который принимает последний активный элемент и клонирует его с новыми значениями и устанавливает активный флаг в true. Моя проблема в том, что метод update вызывается несколькими методами 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, то

  • ли вызовы методов возвращают Наблюдаемые
  • AWAIT наблюдаемые вместо задач
  • Соблюдать на выделенном планировщик частично порядка единицу работы
+0

Благодарим вас за ответ. Я обновляю свой вопрос с помощью некоторого модульного теста, поэтому, как я делаю вызов веб-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; 
    } 

Площадь в замке будет работать только один поток в любой момент времени и будет функционировать должным образом.

Нет гарантий поручения на то, что вам придется делать это по-другому - каким образом будет зависеть от того, какие правила вы хотите применить.