Я создаю приложение Xamarin.Forms для iOS и Android, в котором я храню данные и локальную базу данных sqlite и в сети на сервере Azure. Хотя моему приложению требуется подключение к Интернету, которое оно всегда проверяет с помощью подключаемого модуля Connectivity, я обнаружил, что иногда возникает исключение, если пользователь теряет прием ячейки в середине запроса.
Я хочу иметь метод, с помощью которого я могу вызывать все запросы моего сервера, который будет повторять запрос в случае возникновения ошибки. Я также хотел бы иметь возможность запрашивать у пользователя ввод перед повторной попыткой. Поток будет выглядеть так:
Вызов на сервер -> Обнаружено исключение -> Спросить пользователя, хотят ли они повторить попытку -> Повторить
Я нашел пакет Polly, который настроен для обработки повторных попыток try / catch на C #. В настоящее время мой код настроен следующим образом:
public class WebExceptionCatcher<T, R> where T : Task<R>
{
public async Task<R> runTask(Func<T> myTask)
{
Policy p = Policy.Handle<WebException>()
.Or<MobileServiceInvalidOperationException>()
.Or<HttpRequestException>()
.RetryForeverAsync(onRetryAsync: async (e,i) => await RefreshAuthorization());
return await p.ExecuteAsync<R>(myTask);
}
}
Мой метод RefreshAuthorization()
просто отображает DisplayAlert
на текущей странице в основном потоке:
private async Task RefreshAuthorization()
{
bool loop = true;
Device.BeginInvokeOnMainThread(async () =>
{
await DisplayAlert("Connection Lost", "Please re-connect to the internet and try again", "Retry");
loop = false;
});
while (loop)
{
await Task.Delay(100);
}
}
Когда я отлаживаю это и прерываю интернет-соединение. DisplayAlert
никогда не отображается. Происходит одно из двух:
- Выполнение продолжает вызывать мою задачу снова и снова, не завершая
- Выдается
System.AggregateException
со следующим сообщением:
System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request
Кто-нибудь знает, как успешно приостановить выполнение при сбое задачи и дождаться возобновления работы пользователя?
ОБНОВЛЕНИЕ:
После вызова DisplayAlert
внутри метода Device.BeginInvokeOnMainThread
я нашел способ обойти AggregateException
. Однако теперь у меня возникла другая проблема.
Как только я отключаюсь от Интернета, появляется DisplayAlert
, как и положено. Программа ожидает, пока я нажму «Повторить», прежде чем завершить onRetry
функцию, поэтому ожидание RetryForeverAsync
работает правильно. Проблема в том, что если я снова подключаюсь к Интернету, а затем нажимаю «Повторить», он снова и снова терпит неудачу, и снова и снова. Таким образом, даже несмотря на то, что я подключен к Интернету, я застрял в бесконечном цикле запросов на повторное подключение. Кажется, что RetryForeverAsync
просто повторно выбрасывает старое исключение.
Вот как я звоню runTask()
:
Task<TodoItem> t = App.MobileService.GetTable<TodoItem>().LookupAsync(id);
WebExceptionCatcher<Task<TodoItem>, TodoItem> catcher = new WebExceptionCatcher<Task<TodoItem>, TodoItem>();
Затем я попробовал два разных способа вызова runTask, оба с одинаковым результатом неудачной попытки повторной попытки при восстановлении соединения:
TodoItem item = await catcher.runTask(() => t);
or:
TodoItem item = await catcher.runTask(async () => await t);
RetryForeverAsync
? - person JSteward   schedule 26.09.2017