2011-10-17 14 views
0

WebClient用の私の非同期ダウンロード反応拡張です。 「DownloadStringAsync」を何度も呼び出すと、操作が成功するまで何度もやり直しができます。このようなものの、反応方法でリアクティブメソッドを成功するまで再試行する方法

何か:

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

MY CODE:

[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; 
} 
+0

gotoそれは仕事をすることができました – Burimi

答えて

1

あなたのメソッドはホットオブザーバブルを生成します。つまり、新しいサブスクリプションが新しい要求をWebサーバーに作成しないときに、既に読み込みが開始されています。あなたは、別のあなたの方法をラップし、(各サブスクリプション時に新しい要求を作成した寒さに観察を作成するために)Observable.Createを使用する必要があります。

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の以前の実装である、しばらくパブリックメソッドが置き換えられました。

次のようにそれが成功するまで今、あなたは非同期メソッドを再試行することができます

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

Observable.Defer()を使用するとより簡単な方法があります。 –

+0

oops、私はすでに遅延実装を自分で作成しましたが、私はそれを実現できませんでした。再試行(3)後にコンソールに接続します。私の悪い。 –

0

それは非同期関数である場合。繰り返しチェックを行うと、それを同期関数呼び出しに変えたことを意味します。あなたが本当にやりたいことですか?

この非同期関数を呼び出す専用のスレッドを作成し、この関数を呼び出した後に自身をブロックすることができます。このスレッドを作成するときは、非同期関数が返った後に呼び出されるデリゲートを渡します。完了したら、デリゲートにエラーコードを呼び出します。

これはあなたの質問にお答えします。

1

私はあなたがまともな少なくとも一つを持っていると思うの答え「ここではいくつかのコードである」ので、私はより一般的な手の保持に焦点を当てます。

最初に私が見るのはdesign guidelines for Rxです。パラダイムをプル「サブスクリプション」からプッシュへ、またはIEnumerableからIObservableへと移行するのに役立つ短い(34ページ)PDFドキュメントです。

もう少し行きたい場合は、.NETJavaScriptのPDF HOL(ラボでのハンド)があります。他のリソースは、Rxページ(start here)で見つけることができます。

関連する問題