如何不断重试响应式方法,直到它成功
本文关键字:成功 方法 何不断 重试 响应 | 更新日期: 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函数。重复检查意味着你把它变成了一个同步函数调用。你真的想这么做吗?
你可以有一个专用线程调用这个异步函数,并在调用这个函数后阻塞它自己。创建此线程时,向其传递一个委托,该委托应在异步函数返回后调用。完成后,调用带有错误代码的委托。
希望这能回答你的问题