Я использую блок приложений Application Application Transient Fault для обработки приложений в Windows 8 Store с клиентом служб данных WCF для ODATA. Я хочу использовать логику повтора для временных ошибок, возникающих при вызове службы ODATA. Я создал специальную стратегию обнаружения ошибок при переходе.EntLib TransientFaultHandling RetryPolicy.ExecuteAsync-контекст синхронизации
Я также построил метод расширения LoadTaskAsync для DataServiceCollection, поскольку метод LoadAsync не возвращает задачу (вместо этого DataServiceCollection вызывает событие LoadCompleted).
Так что я могу загрузить данные в DataServiceCollection следующим образом:
var query = this.DataContext.Products.Where(item => item.Modified >= anchor);
var products = new DataServiceCollection<Product>(this.DataContext);
await this.retryPolicy.ExecuteAsync(() => products.LoadTaskAsync(query));
Теперь документация по Enterprise Library Transient Обработка ошибок Блок приложений утверждает, что
taskFunc аргумент вы передаете ExecuteAsync метод не обязательно вызывается в том же контексте синхронизации, который использовался при вызове ExecuteAsync изначально; поэтому, если вам нужно запустить задачу из потока пользовательского интерфейса, например, не забудьте запланировать его явно внутри делегата.
Мне нужно вызвать метод LoadTaskAsync в потоке пользовательского интерфейса, поскольку операция загрузки может обновлять продукты, которые уже отслеживаются контекстом данных и которые связаны данными с пользовательским интерфейсом.
Вопрос в том, как? Предпочтительно, не изменяя метод расширения LoadTaskAsync (что, если бы не мой код для изменения). Я думал о создании метода расширения для RetryPolicy, который вызывает метод ExecuteAsync, при этом убедитесь, что taskFunc вызывается в потоке пользовательского интерфейса.
Самый простой способ, возможно, является изменение метода расширения LoadTaskAsync пройти в TaskCreationOptions.AttachedToParent, так что я мог бы создать метод расширения для RetryPolicy следующим образом:
public static Task<TResult> ExecuteCurrentSynchronizationContextAsync<TResult>(
this RetryPolicy retryPolicy,
Func<TaskCreationOptions, Task<TResult>> taskFunc)
{
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
return
retryPolicy.ExecuteAsync(
() =>
Task.Factory.StartNew(
() => taskFunc(TaskCreationOptions.AttachedToParent),
CancellationToken.None,
TaskCreationOptions.None,
scheduler).Unwrap());
}
Обратите внимание, что taskFunc теперь должен быть Func < TaskCreationOptions, Task <TResult> >.
Я бы тогда называть это следующим образом:
await
this.retryPolicy.ExecuteCurrentSynchronizationContextAsync(
creationOptions => products.LoadTaskAsync(query, creationOptions));
Я предпочитаю не менять метод расширения LoadTaskAsync, как я мог бы изменить этот метод расширения RetryPolicy ExecuteCurrentSynchronizationContextAsync так, что taskFunc может быть Func < Задача <TResult> > еще раз убедитесь, что taskFunc вызывается в потоке пользовательского интерфейса?
Блестящее решение. Это подходит для меня. Большое спасибо. –