2016-04-22 1 views
0

CustomWebClientオブジェクトを使用して1つ以上の小さなファイル(サイズが400KB未満で、一度に20KB未満のjpg)をダウンロードしているデスクトップアプリケーションがありますOpenReadAsync()を呼び出します。プロセスに問題がなければ、ダウンロードプロセスは正常に動作しています。応答をある時間(15秒)に制限したいので、要求を中止するtimeOut処理を導入しました。タイムアウトしても動作し、その後私の "OpenReadCompletedEventHandler"メソッドはSystem.Net.WebExceptionを受信して​​います:要求が中止されました:要求がキャンセルされました(これは正しい動作です)。 私の問題は、ユーザーに写真の再読み込みを試行させたいということです。したがって、次のwebClientリクエストは同じWebExceptionで失敗しています。以下は私のコードです。ここでタイムアウトしてアボートした後に2回目のWebClientリクエストを実行できない

(一度に2つの以上の非同期接続を持っているために使用される)私のカスタムWebClientクラスである:ここで

internal class ExtendedWebClient : WebClient 
{ 
    private Timer _timer; 
    public int ConnectionLimit { get; set; } 
    public int ConnectionTimeout { get; set; } 
    public ExtendedWebClient() 
    { 
     this.ConnectionLimit = 2; 
    } 

    protected override WebRequest GetWebRequest(Uri address) 
    { 
     var request = base.GetWebRequest(address) as HttpWebRequest; 

     if (request != null){_timer = new Timer(TimeoutRequest, request, ConnectionTimeout, Timeout.Infinite); 

      request.ServicePoint.ConnectionLimit = this.ConnectionLimit; 
      request.ServicePoint.MaxIdleTime = 5000; 
      request.ServicePoint.ConnectionLeaseTimeout = 5000; 
     } 

     return request; 
    } 

    private void TimeoutRequest(object state) 
    { 
     _timer.Dispose(); 
     _timer = null; 
     ((WebRequest)state).Abort(); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (_timer != null) 
     { 
      _timer.Dispose(); 
      _timer = null; 
     } 
     base.Dispose(disposing); 
    }  
} 

は私のカスタムWebClientクラスを使用してファイルをダウンロードするためのコードです:

私がチェックした画像にアクセスしたいとき
internal struct PageWaitHandleState 
{ 
    public int WaitHandleIndexInPage; 
    public bool ImageIsLoaded; 
    public string ErrMessage; 
} 

public Image[] downloadedImages; 

private PageWaitHandleState[] waitHandlesInPage; 
private OpenReadCompletedEventHandler[] downloadComplete; 
private EventWaitHandle[] pagesEWH = null; 
private EventWaitHandle[] downloadImageEvent; 
private int availableImages = 1; // Set here to simplify, but as I stated in my description, it may be more than 1. 
int downloadTimeOut = 15000; 
int maxSimultaneousDownloads = 20; 

private void DownloadImages(int pageIndex = 0, string[] imageUrl) 
{ 
    if (pagesEWH[pageIndex] != null) 
    { 
     ReloadImages(pageIndex, imageUrl); // Executed in the second request 
     return; 
    else 
    { 
     pagesEWH[pageIndex] = new EventWaitHandle[availableImages]; 
     downloadedImages = new Image[availableImages]; 
     downloadComplete = new OpenReadCompletedEventHandler[availableImages]; 
     downloadImageEvent = new EventWaitHandle[availableImages]; 
     waitHandlesInPage = new PageWaitHandleState[availableImages]; 

     // Set the downloadComplete deletages 
     for (int i = 0; i < availableImages; i++) 
     { 
      downloadComplete[i] = ProcessImage; 
     } 
    } 

    for (int imgCounter = 0; i < availableImages; i++) 
    { 
     waitHandlesInPage[imgCounter] = new PageWaitHandleState() { ImageIsLoaded = false, WaitHandleIndexInPage = imgCounter, ErrMessage = null }; 
     downloadImageEvent[imgCounter] = GrabImageAsync(imageUrl[imgCounter], downloadComplete[imgCounter], imgCounter, downloadTimeOut, maxSimultaneousDownloads); 
     pagesEWH[imgCounter] = downloadImageEvent[imgCounter]; 
    } 

     offenderIndex++; 
    } 
} 

private static EventWaitHandle GrabImageAsync(string url, OpenReadCompletedEventHandler openReadCompletedEventHandler, int imgCounter, int downloadTimeOut, int maxSimultaneousDownloads) 
{ 
    var myClient = new ExtendedWebClient(); 
    myClient.ConnectionLimit = maxSimultaneousDownloads; 
    myClient.ConnectionTimeout = downloadTimeOut; 
    myClient.OpenReadCompleted += openReadCompletedEventHandler; 
    var iewh = new ImageEventWaitHandle() { ewh = new EventWaitHandle(false, EventResetMode.ManualReset), ImageIndex = imgCounter }; 
    myClient.OpenReadAsync(new Uri(url), iewh); 
    return iewh.ewh; 
} 

internal void ProcessImage(object sender, OpenReadCompletedEventArgs e) 
{ 
    ImageEventWaitHandle iewh = (ImageEventWaitHandle)e.UserState; 
    bool disposeObject = false; 

    try 
    { 
     if (e.Cancelled) 
     { 
      this.waitHandlesInPage[iewh.ImageIndex].ImageIsLoaded = false; 
      this.waitHandlesInPage[iewh.ImageIndex].ErrMessage = "WebClient request was cancelled"; 
     } 
     else if (e.Error != null) 
     { 
      this.waitHandlesInPage[iewh.ImageIndex].ImageIsLoaded = false; 
      this.waitHandlesInPage[iewh.ImageIndex].ErrMessage = e.Error.Message; 
      iewh.ewh.Set(); 
      this.downloadImageEvent[iewh.ImageIndex].Close(); 
     } 
     else 
     { 
      using (Stream inputStream = e.Result) 
      using (MemoryStream ms = new MemoryStream()) 
      { 
       byte[] buffer = new byte[4096]; 
       int bytesRead; 
       int totalReadBytes = 0; 
       do 
       { 
        bytesRead = inputStream.Read(buffer, 0, buffer.Length); // Exception fired here with the second request 
        ms.Write(buffer, 0, bytesRead); 
        totalReadBytes += bytesRead; 
       } while (inputStream.CanRead && bytesRead > 0); 

       this.downloadedImages[iewh.ImageIndex] = Image.FromStream(ms); 
       this.waitHandlesInPage[iewh.ImageIndex].ImageIsLoaded = true; 
       this.waitHandlesInPage[iewh.ImageIndex].ErrMessage = null; 
      } 
      disposeObject = true; 
     } 
    } 
    catch (Exception exc) 
    { 
     this.downloadedImages[iewh.ImageIndex] = null; 
    } 
    finally 
    { 
     // Signal the wait handle 
     if (disposeObject) 
     { 
      iewh.ewh.Set(); 
      ((WebClient)sender).Dispose(); 
     } 
    } 
} 

private void ReloadImages(int pageIndex, string[] imageUrl) 
{ 
    for (int imgCounter = 0; imgCounter < availableImages; imgCounter++) 
    { 
     this.downloadComplete[imgCounter] = this.ProcessImage; 
     this.waitHandlesInPage[imgCounter] = new PageWaitHandleState() { ImageIsLoaded = false, WaitHandleIndexInPage = imgCounter, ErrMessage = null }; 
     this.downloadImageEvent[imgCounter] = GrabImageAsync(ImageUrl[imgCounter],this.downloadComplete[imgCounter], imgCounter, downloadTimeOut, maxSimultaneousDownloads); 
     this.pagesEWH[imgCounter] = this.downloadImageEvent[imgCounter]; 
    } 
} 
最後に

、彼らが使用して準備ができている場合:

private bool ImagesInPageReady(int pageIndex, int recordsInCurrentPage) 
{ 
    if (_PagesEWH[pageIndex] != null) 
    { 
     int completedDownloadsCount = 0; 
     bool waitHandleSet; 

     // Wait for the default images first (imgCounter = 0). When moving page or asking for more pictures, then wait for the others. 
     for (int ewhIndexInPage = 0; ewhIndexInPage < recordsInCurrentPage; ewhIndexInPage++) 
     { 
      if (this.pagesEWH[ewhIndexInPage].WaitOne(this.downloadTimeOut)) 
      { 
       if (this.WaitHandlesInPage[ewhIndexInPage].ImageIsLoaded) 
       { 
        completedDownloadsCount++; 
       } 
      } 
      else 
      { 
       this.pagesEWH[ewhIndexInPage].Set(); 
      } 
     } 

     return (completedDownloadsCount > 0); 
    } 

    return false; 
} 
+0

これは質問にとって重要ではありませんが、ここでは多くのAPIが廃止されています。おそらくTPLと 'HttpClient'と' await'を使ってコードを半分に縮小することができます。 – usr

+0

私は.NET 4を使用していますので、残念ながら、私はawaitを使用することはできません。あなたのコメントをどうもありがとう。 –

+0

4.0でawaitを使用できます。 – usr

答えて

0

@usr、私を正しい方向に向けることに感謝します。 HttpClientがソリューションでした。だから、私は基本的に、新しいクラスにHttpClientオブジェクトをカプセル化し、ProcessImage()メソッドとエクスポーティングとイベントを同じメソッドで起動しました。

関連する問題