(Примечание: это слишком упрощенный сценарий, демонстрирующий мою проблему кодирования.)
У меня есть следующий интерфейс класса:
public class CustomerService
{
Task<IEnumerable<Customer>> FindCustomersInArea(String areaName);
Task<Customer> GetCustomerByName(String name);
:
}
Это клиентская частьRESTful API, который загружает список объектов Customer с сервера, затем предоставляет методы, позволяющие клиентскому коду использовать и работать с этим списком.
Оба эти метода работают с внутренним списком клиентов, полученным с сервера, следующим образом:
private Task<IEnumerable<Customer>> LoadCustomersAsync()
{
var tcs = new TaskCompletionSource<IEnumerable<Customer>>();
try
{
// GetAsync returns Task<HttpResponseMessage>
Client.GetAsync(uri).ContinueWith(task =>
{
if (task.IsCanceled)
{
tcs.SetCanceled();
}
else if (task.IsFaulted)
{
tcs.SetException(task.Exception);
}
else
{
// Convert HttpResponseMessage to desired return type
var response = task.Result;
var list = response.Content.ReadAs<IEnumerable<Customer>>();
tcs.SetResult(list);
}
});
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
Класс Client - это пользовательская версия класса HttpClient из веб-API WCF (теперь ASP.NET Web API), потому что я работаю в Silverlight, и у них нет SL-версииих клиентские сборки.
После всего этого, вот моя проблема:
Все методы в классе CustomerService используют список, возвращаемый асинхронным методом LoadCustomersAsync;поэтому любые вызовы этих методов должны ждать (асинхронно), пока метод LoadCustomers не вернется и логика appopriate будет выполнена в возвращенном списке.
Я также хочу, чтобы только один вызов был сделан из клиента (в LoadCustomers) ввремя.Итак, мне нужно, чтобы все вызовы открытых методов ожидали выполнения одной и той же внутренней задачи.
Чтобы рассмотреть, вот что мне нужно, чтобы выяснить, как выполнить:
Любой вызов FindCustomersInArea и GetCustomerByName должен возвращать задачу, ожидающую завершения метода LoadCustomersAsync.Если LoadCustomersAsync уже вернулось (и кэшированный список все еще действителен), то метод может продолжиться немедленно.
После возврата LoadCustomersAsync у каждого метода есть дополнительная логика, необходимая для преобразования списка в требуемыйвозвращаемое значение для метода.
Всегда должен быть только один активный вызов LoadCustomersAsync (внутри метода GetAsync).
Еслисрок действия кэшированного списка истекает, затем последующие вызовы вызовут перезагрузку (через LoadCustomersAsync).
Дайте мне знать, если вам нужны дополнительные разъяснения, но я надеюсь, что это достаточно распространенный вариант использования, которыйкто-то может помочь мне проработать логику, чтобы заставить клиента работать так, как нужно.