2011-09-08 60 views
4

我有一個類「圖像」具有三個屬性:URL,ID,內容。 我有10個這樣的圖像列表。 這是一個silverlight應用程序。並行HttpWebRequests與無擴展

我想創建一個方法:

IObservable<Image> DownloadImages(List<Image> imagesToDownload) 
{ 
    //start downloading all images in imagesToDownload 
    //OnImageDownloaded: 
          image.Content = webResponse.Content 
          yield image 

} 

這種方法開始下載並行所有10張圖像。 然後,每個下載完成時,它會將Image.Content到下載的WebResponse.Content。

結果應該是一個的IObservable流與每個下載的圖像。

我在RX初學者,我覺得我想可以用ForkJoin達到什麼樣的,但是這是在反應擴展DLL的實驗版本,我不想使用。

而且我真的不喜歡下載的回調計數檢測,所有圖像下載完畢後,然後調用onCompleted()。

似乎並沒有被在Rx精神給我。

我也張貼到目前爲止,我什麼編碼的解決方案,雖然我不喜歡我的解決方案,因爲它的長/醜,並使用計數器。

 return Observable.Create((IObserver<Attachment> observer) => 
     { 
      int downloadCount = attachmentsToBeDownloaded.Count; 
       foreach (var attachment in attachmentsToBeDownloaded) 
         { 
          Action<Attachment> action = attachmentDDD => 
          this.BeginDownloadAttachment2(attachment).Subscribe(imageDownloadWebResponse => 
           { 
            try 
            { 
             using (Stream stream = imageDownloadWebResponse.GetResponseStream()) 
             { 
              attachment.FileContent = stream.ReadToEnd(); 
             } 
             observer.OnNext(attachmentDDD); 

             lock (downloadCountLocker) 
             { 
              downloadCount--; 
              if (downloadCount == 0) 
              { 
               observer.OnCompleted(); 
              } 
             } 
            } catch (Exception ex) 
            { 
             observer.OnError(ex); 
            } 
           }); 
          action.Invoke(attachment); 
         } 

         return() => { }; //do nothing when subscriber disposes subscription 
        }); 
      } 

好吧,我確實管理它,使它的工作最終根據吉姆的答案。

var obs = from image in attachmentsToBeDownloaded.ToObservable() 
       from webResponse in this.BeginDownloadAttachment2(image).ObserveOn(Scheduler.ThreadPool) 
       from responseStream in Observable.Using(webResponse.GetResponseStream, Observable.Return) 
       let newImage = setAttachmentValue(image, responseStream.ReadToEnd()) 
       select newImage; 

其中setAttachmentValue只需要`image.Content = bytes;返回圖像;

BeginDownloadAttachment2代碼:

 private IObservable<WebResponse> BeginDownloadAttachment2(Attachment attachment) 
    { 
     Uri requestUri = new Uri(this.DownloadLinkBaseUrl + attachment.Id.ToString(); 
     WebRequest imageDownloadWebRequest = HttpWebRequest.Create(requestUri); 
     IObservable<WebResponse> imageDownloadObservable = Observable.FromAsyncPattern<WebResponse>(imageDownloadWebRequest.BeginGetResponse, imageDownloadWebRequest.EndGetResponse)(); 

     return imageDownloadObservable; 
    } 
+0

很高興提供幫助。我不得不說,解決方案看起來比開始的維護容易得多。 –

+0

良好的使用。很好的解決方案。 –

回答

3

怎麼樣,我們簡化了這個有點。把你的圖像列表,並將其轉換爲可觀察的。接下來,考慮使用Observable.FromAsyncPattern來管理服務請求。最後使用SelectMany將請求與響應進行協調。我正在做一些關於如何在這裏獲取文件流的假設。本質上,如果您可以將您的服務請求的BeginInvoke/EndInvoke委託傳入到FromAsyncPattern中,那您就很好。

var svcObs = Observable.FromAsyncPattern<Stream>(this.BeginDownloadAttachment2, This.EndDownloadAttchment2); 

var obs = from image in imagesToDownload.ToObservable() 
      from responseStream in svcObs(image) 
      .ObserveOnDispatcher() 
      .Do(response => image.FileContent = response.ReadToEnd()) 
      select image; 
return obs; 
+0

謝謝吉姆。它幾乎不錯。我遇到的唯一問題是BeginDownloadAttachment2返回一個IObservable 。我嘗試了代碼轉換爲:... DO(響應=> Observable.Using(response.GetResponseStream,溪流=> image.FileContent = stream.ReadToEnd())),但我得到一些錯誤:類型參數不能從使用推斷。 –

+0

其實我覺得我找到了:... DO(響應=> Observable.Using(response.GetResponseStream,流=> Observable.Return(stream.ReadToEnd()))做(字節=> image.Value。 FileContent = bytes))。將測試並查看它是否有效。 –

+0

沒有工作:( –