我正在为 iOS 和 Android 创建一个 Xamarin.Forms 应用程序,我在其中保存数据和本地 sqlite 数据库并在 Azure 服务器中联机。尽管我的应用程序需要 Internet 连接,并且它始终使用 Connectivity 插件进行检查,但我发现如果用户在请求中丢失单元接收,我有时会抛出异常。
我想要一个方法,我可以调用我所有的服务器请求,如果发生错误,它将重试请求。我还希望能够在重试之前要求用户输入。流程如下所示:
调用服务器 --> 异常捕获 --> 询问用户是否要重试 --> 重试
我找到了Polly包,它设置为在 C# 中处理 try/catch 重试。我目前的代码设置如下:
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
从未显示。发生以下两种情况之一:
- 执行继续一遍又一遍地调用我的任务而没有完成
- 抛出A
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);
或者:
TodoItem item = await catcher.runTask(async () => await t);