如何不断重试响应式方法,直到它成功

本文关键字:成功 方法 何不断 重试 响应 | 更新日期: 2023-09-27 18:11:35

这是我的WebClient异步下载响应式扩展。什么是最好的方式来回忆"DownloadStringAsync"一次又一次,直到操作成功?

类似于这样,但以一种被动的方式:

while (true)
{
  var result = DownloadStringAsync();
  if (result)
  {
    return;
  }
}

我代码:

[Serializable]
public class WebClientException : Exception
{
    public WebClientResponse Response { get; set; }
    public WebClientException()
    {
    }
    public WebClientException(string message)
        : base(message)
    {
    }
    public WebClientException(string message, Exception innerException)
        : base(message, innerException)
    {
    }
    protected WebClientException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }
}
public class WebClientResponse
{
    public WebHeaderCollection Headers { get; set; }
    public HttpStatusCode StatusCode { get; set; }
    public string Result { get; set; }
    public WebException Exception { get; set; }
}
public static IObservable<WebClientResponse> DownloadStringAsync(this WebClient webClient, Uri address, WebHeaderCollection requestHeaders)
{
    var asyncResult =
        Observable.FromEventPattern<DownloadStringCompletedEventHandler, DownloadStringCompletedEventArgs>
            (ev => webClient.DownloadStringCompleted += ev, ev => webClient.DownloadStringCompleted -= ev)
            .ObserveOn(Scheduler.TaskPool)
            .Select(o =>
                        {
                            var ex = o.EventArgs.Error as WebException;
                            if (ex == null)
                            {
                                var wc = (WebClient) o.Sender;
                                return new WebClientResponse {Headers = wc.ResponseHeaders, Result = o.EventArgs.Result};
                            }
                            var wcr = new WebClientResponse {Exception = ex};
                            var r = ex.Response as HttpWebResponse;
                            if (r != null)
                            {
                                wcr.Headers = r.Headers;
                                wcr.StatusCode = r.StatusCode;
                                var s = r.GetResponseStream();
                                if (s != null)
                                {
                                    using (TextReader tr = new StreamReader(s))
                                    {
                                        wcr.Result = tr.ReadToEnd();
                                    }
                                }
                            }
                            throw new WebClientException {Response = wcr};
                        })
            .Take(1);
    if (requestHeaders != null)
    {
        foreach (var key in requestHeaders.AllKeys)
        {
            webClient.Headers.Add(key, requestHeaders[key]);
        }
    }
    webClient.DownloadStringAsync(address);
    return asyncResult;
}

如何不断重试响应式方法,直到它成功

你的方法产生了一个热可观察对象,这意味着当它返回时它已经开始加载,并且每个新的订阅都不会向web服务器创建新的请求。你需要把你的方法包装在另一个方法中,并使用Observable。创建(为了创建一个在每次订阅时创建新请求的冷可观察对象):

public static IObservable<WebClientResponse> DownloadStringAsync(this WebClient webClient, Uri address, WebHeaderCollection requestHeaders)
{
    return Observable
        .Create(observer => 
        {
            DownloadStringAsyncImpl(webClient, address, requestHeaders)
                .Subscribe(observer);
            return () => { webClient.CancelAsync(); };
        });
}

这里,DownloadStringAsyncImpl是你之前的DownloadStringAsync的实现,而公共方法已经被替换了。

现在你可以重试async方法,直到它成功,如下所示:

myWebClient
    .DownloadStringAsync( /* args... */)
    .Retry()
    .Subscribe(result => { 
         /* now I've got a result! */
    });

我认为你至少有一个体面的"这是一些代码"的答案,所以我将重点放在更一般的手把手。

我首先要看的是Rx的设计指南。这是一个简短的(34页)PDF文档,它帮助将范式从拉式"订阅"转变为推送式,或者从IEnumerable转变为IObservable。

如果你想更进一步,有。net和JavaScript的PDF HOLs(动手实验)。您可以在Rx页面上找到其他资源(从这里开始)。

如果是async函数。重复检查意味着你把它变成了一个同步函数调用。你真的想这么做吗?

你可以有一个专用线程调用这个异步函数,并在调用这个函数后阻塞它自己。创建此线程时,向其传递一个委托,该委托应在异步函数返回后调用。完成后,调用带有错误代码的委托。

希望这能回答你的问题