当前位置: 首页 > 知识库问答 >
问题:

C#Polly Async-await:等待用户确认后再重试

黄锋
2023-03-14

我找到了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); 
    }
}

当我调试这个并切断我的internet连接时。从不显示DisplayAlert。发生两件事之一:

    null

更新:

在将对DisplayAlert的调用放到Device.BeginInvokeonMainThread方法中之后,我现在找到了绕过AggregateException的方法。然而,现在我又有了一个问题。

一旦我断开与internet的连接,displayalert就会像应该的那样弹出。程序在完成onretry函数之前等待我单击重试,以便retryforeVerAsync等待工作正常。问题是,如果我重新连接到互联网,然后点击重试,它会一次又一次地失败。因此,即使我连接到互联网,我也陷入了被要求重新连接的无限循环。似乎RetryForeVerAsync只是重新抛出旧的异常。

Task<TodoItem> t = App.MobileService.GetTable<TodoItem>().LookupAsync(id);
WebExceptionCatcher<Task<TodoItem>, TodoItem> catcher = new WebExceptionCatcher<Task<TodoItem>, TodoItem>();
TodoItem item = await catcher.runTask(() => t);
TodoItem item = await catcher.runTask(async () => await t);

共有1个答案

龚远
2023-03-14

您需要使用.RetryForeVerAsync(...)作为注释。然后,由于重试委托是异步的,因此还需要使用onRetryAsync:。因此:

.RetryForeVerAsync(onRetryAsync:async(e,i)=>await RefreshAuthorization());

为了解释您看到的错误:在问题中的代码示例中,通过使用onretry:,您指定要使用同步onretry委托(返回void),但随后为其分配异步委托。

使async-delegate-assigned-to-sync-param变为Async void;调用代码不/等不及了。由于不等待异步空号委托,因此执行的委托确实会不断重试。

System.AggregateException:未观察到任务的异常可能是由该异常引起的,也可能是由MyTask的签名不匹配引起的(在发布此答案时q中不可用)。

编辑以回应问题和进一步评论的更新:

我知道(作为Polly的作者/维护者),Polly每次循环时都会调用传递的func > ,并且只会重新抛出新执行func > 抛出的任何异常。请参见异步重试实现:它每次在重试循环中重新尝试用户委托。

您可以尝试对调用代码进行以下(临时的、诊断性的)修改,以查看refreshAuthorization()是否真的阻止调用策略代码继续执行,同时等待用户单击重试。

public class WebExceptionCatcher<T, R> where T : Task<R>
{      
    public async Task<R> runTask(Func<T> t)
    {
        int j = 0;
        Policy p = Policy.Handle<WebException>()
        .Or<MobileServiceInvalidOperationException>()
        .Or<HttpRequestException>()
        .RetryForeverAsync(onRetryAsync: async (e,i) => await RefreshAuthorization());

        return await p.ExecuteAsync<R>( async () => 
        {
            j++;
            if ((j % 5) == 0) Device.BeginInvokeOnMainThread(async () =>
            {
                 await DisplayAlert("Making retry "+ i, "whatever", "Ok");
            });
            await myTask;
        });
    }
}

如果refreshAuthorization())正确阻止,则在显示Making Retry5对话框之前,您需要将Connection Lost弹出窗口取消五次。

如果refreshAuthorization())没有阻止调用代码,则在重新连接之前,策略将继续在后台进行多次(失败)尝试,并首先取消Connection Lost对话框。如果这种情况成立,然后只取消Connection Lost弹出一次,则将看到弹出making retry 5Make retry 10(等等);可能更多),在下一个连接丢失弹出之前。

使用这个(临时的、诊断性的)修改还应该证明每次Polly都在重新执行您传递的委托。如果MyTask引发了相同的异常,那么MyTask可能会出现问题--我们可能需要对此有更多的了解,并进行更深入的研究。

更新以响应发起人的第二次更新,开始“以下是我如何调用runtask():

所以:您一直在假设重试失败,但您构造的代码实际上不进行任何重试。

剩下的问题的来源是这两行:

Task<TodoItem> t = App.MobileService.GetTable<TodoItem>().LookupAsync(id);
TodoItem item = await catcher.runTask(() => t); // Or same effect: TodoItem item = await catcher.runTask(async () => await t);

无论Polly策略如何(如果您使用手工构建的whilefor循环进行重试,则只调用app.mobileService.gettable ().lookupasync(id) 一次)。

Task<TodoItem> t = App.MobileService.GetTable<TodoItem>().LookupAsync(id);

为了从图片中去掉任务来说明问题,它有点像编写以下代码:

int i = 0;
int j = i++;
Func<int> myFunc = () => j;
for (k=0; k<5; k++) Console.Write(myFunc());

并希望它打印12345,而不是(它将打印J的值五次)11111

为了让它工作,简单地说:

TodoItem item = await catcher.runTask(() => App.MobileService.GetTable<TodoItem>().LookupAsync(id));
 类似资料:
  • 有什么想法吗?没有JS库。 编辑:我做了几次回拨尝试。老实说,我很难理解他们。下面是我的最后一次尝试:

  • 问题内容: 我正在尝试制作一个暂停用户输入的简单命令。我认为在Bash脚本中它将很有用。 这是我的代码: 它甚至不会暂停供用户输入。 我之前尝试过使用getch()(ncurses)。发生的是,屏幕变黑了,当我按下一个键时,它又回到了原来的屏幕上,我看到了: 这是我想要的。但是我想要的只是DOS / Windows 中的命令(我使用Linux)。 问题答案: 从GNU C库手册: 函数:char

  • 尝试学习Async/await(以下代码),等待在2s后返回用户名。(返回一个promise)然后只记录接收到的用户名。 问题是then方法中的记录了。 不确定这里出了什么问题。很感谢解释一下这里到底发生了什么。 多谢了。

  • 问题内容: 我过去一直在努力,今天一直在努力的事情是阻止API / AJAX继续进行,直到您收到响应为止。目前,我正在使用Facebook API。我需要从调用中获取响应,然后将其返回,但是正在发生的事情是,在我从未从API调用中获取响应之前,我的函数正在返回。我知道为什么会这样,我只是想不出如何预防!这是我的代码… // -----编辑 我注意到有人建议这样的事情… 但这返回未定义 //根据更新

  • 我在用硒检查搜索结果。我想检查搜索结果并移到详细页。所以,我用了两次'WebDriverWait Until'。第一次等待似乎很有效,但第二次等待就不起作用了。 当我添加time.sleep(0.5)时,它起作用了。但是,我不想为了这个而睡觉。 你们能看看我的剧本吗?为了测试,我已经在脚本中输入了IP地址。我以后再换。

  • 问题内容: 基本上,一旦用户在我的应用程序中离开了网页,我就需要使用AJAX调用PHP脚本,这会将在网页上花费的时间插入数据库中,然后离开该页面。 重要的是要等待AJAX​​请求完成,因为用户无法访问我的应用程序中的网页,除非用户在前一页上花费了一定的时间(例如两分钟)。 这是我的jQuery代码: 我应该如何更改它,以便它将在离开网页之前等待AJAX​​请求结束? 编辑: 或者,最好每隔一分钟左