2012-04-02 62 views
0

我正在使用WebClient從服務器獲取一些JSON數據。我希望它是同步的(是的,我知道在WP中一切都應該是異步的,但我需要它從某種原因同步)。在我的課,我有這樣的代碼:WebClient - 大數據同步響應

private WebClient _webClient; 
    private string _acctualResponse; 
    private AutoResetEvent _lock = new AutoResetEvent(false); 

    void _webClient_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e) 
    { 
     _acctualResponse = e.Result; 
     _lock.Set(); 
    } 

    public string _message; 
    public string SendString(string URL, string message) 
    { 
     _webClient.UploadStringAsync(new Uri(URL), message); 
     _lock.WaitOne(); 
     return _acctualResponse;  
    } 

在我的計劃,我用它來得到一些不同的數據集。一切正常,而返回數據很小。當我必須獲得更大的數據(3個img base64),事件不是開始。 但是! 當我刪除_lock時,事件總是在SendString函數結束後開始片刻。我嘗試使用一些其他機制等待響應,例如while循環:

private void WaitForResponse() 
    { 
     _acctualRequestTime = 0; 
     _acctualResponse = null; 
     while (!_uploadComplet && _acctualRequestTime < Timeout) 
     { 
      int slepTime = 200; 
      Thread.Sleep(slepTime); 
      _acctualRequestTime += slepTime; 
     } 
     _uploadComplet = false; 
    } 

[當然,在事件中,我被_uploadComplete標誌設置爲true] 效應是相同的:反應過來一個短暫停後,不管是什麼超時間隔設置。 我對這種情況有點困惑。你知道我做得不好嗎?

+0

你在與異步設計理念相悖,但你不明白爲什麼。也許你可以爲此寫下你的理由,我們可以給你一個解決你的問題的答案,但不要求你跳過這些圈套? – 2012-04-02 09:46:15

回答

1

我也有這個問題。

您可以使用此:

public T Get<T>(string apiMethod) where T : class 
     { 
      T outputObject; 
      lock (syncObj) 
      { 
       downloadHandle = new ManualResetEvent(false); 

       ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadAsync), apiMethod); 
       downloadHandle.WaitOne(); 
       outputObject = JsonHelper.Parse<T>(result); 
      } 
      return outputObject; 
     } 

protected void DownloadAsync(object _uri) 
     { 
      try 
      { 
       var url = _uri as string; 
       WebClient client = new WebClient(); 
       client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted); 
       client.DownloadStringAsync(new Uri(GLOBALS.MAIN_API_URL + url, UriKind.Absolute)); 
      } 
      catch (Exception ex) 
      { 
       downloadHandle.Set(); 
      } 
     } 

void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) 
     { 
      (sender as WebClient).DownloadStringCompleted -= client_DownloadStringCompleted; 

      try 
      { 
       result = e.Result; 
      } 
      catch (Exception ex) 
      { 
       result = ex.Message; 
      } 
      finally 
      { 
       downloadHandle.Set(); 
      } 
     } 

現在你可以使用這樣的:

public Song GetSong(int _id) 
     { 
      var wr = Get<SongInfoWrapper>("info/song/" + _id); 
      if (wr != null) 
      { 
       if (wr.Error == null) 
       { 
        return wr.Element; 
       } 
      } 

      return null; 
     } 

不過可以肯定的是,在UI線程調用不GetSong方法。

0

WebClient如果請求已在UI線程上啓動,則會在UI線程上引發事件。因此,如果您在UI線程中等待並且不對主事件循環進行控制,則這些事件將排隊等待,因此從未交付。

由於WebClient在UI線程上執行所有處理,所以Microsoft和其他許多人建議不要使用它。應該使用WebRequest。它甚至可以解決你的問題。 (儘管屏蔽UI線程並不是一件好事。)

+0

我也試過'WebRequest'。效果是一樣的:( – Thaven 2012-04-02 10:48:17

+0

您可能需要在後臺線程上啓動WebRequest,否則該事件無法傳遞給阻塞的UI線程。 – Codo 2012-04-02 10:51:22