2012-04-02 4 views
0

Ich verwende WebClient, um einige JSON-Daten vom Server abzurufen. Und ich möchte, dass es synchron ist (ja, ich weiß, dass in WP alles async sein sollte, aber ich brauche es aus irgendeinem Grund synchronisieren). In meiner Klasse habe ich Code wie folgt:WebClient - Antwort mit großen Daten synchronisieren

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;  
    } 

In meinem Programm verwende ich es ein paar anderen Datensatz zu erhalten. Und alles funktioniert OK, während die Rückgabedaten klein sind. Wenn ich größere Daten bekommen muss (3 img in base64), werden Ereignisse nicht gestartet. ABER! wenn ich _lock löste, Ereignis immer einen Moment nach SendString Funktion beginnt, ist vorbei. Ich versuche, einige andere Mechanismen zu verwenden, um auf eine Antwort zu warten, z. while Schleife:

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

[natürlich in Ereignis i einstellte _uploadComplete Flag auf true] Efect war das gleiche: Antwort kam eine kurze nach Timeout, egal welche Timeout-Zeit eingestellt wurde. Ich bin ein bisschen verwirrt durch diese Situation. Weißt du, was ich schlecht mache?

+0

Sie rennen gegen die erwartete asynchrone Designphilosophie, aber Sie sagen nicht warum. Vielleicht könnten Sie Ihren Grund dafür aufschreiben, und wir könnten Ihnen eine Antwort geben, die Ihr Problem löst, aber Sie müssen nicht durch diese Reifen springen? –

Antwort

1

Ich hatte dieses Problem auch.

Sie können diese verwenden:

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(); 
      } 
     } 

jetzt können Sie wie folgt verwenden:

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

      return null; 
     } 

aber sicher sein, dass GetSong Methode nicht in UI-Thread aufgerufen.

0

WebClient löst die Ereignisse im UI-Thread aus, wenn die Anforderung im UI-Thread gestartet wurde. Wenn Sie also auf den UI-Thread warten und die Hauptereignisschleife nicht steuern, werden die Ereignisse in die Warteschlange gestellt und somit nie geliefert.

Da WebClient die gesamte Verarbeitung auf dem UI-Thread verarbeitet, empfehlen Microsoft und viele andere, es nicht zu verwenden. Stattdessen sollte WebRequest verwendet werden. Es könnte sogar dein Problem lösen. (Obwohl das Blockieren des UI-Threads nicht gerade eine gute Sache ist.)

+0

Ich habe auch 'WebRequest' versucht. Der Effekt war der gleiche :( – Thaven

+0

Sie müssen wahrscheinlich die WebRequest auf einem Hintergrundthread starten. Andernfalls kann das Ereignis auch nicht an Ihren blockierenden UI-Thread geliefert werden. – Codo