2012-03-26 2 views
4

Ich bin ein wenig verwirrt. Ich versuche, asynchron auf meinem Web-Service zu veröffentlichen, idealerweise möchte ich die Anfrage starten, ein Lade-Spinner auf der Benutzeroberfläche anzeigen und dann, wenn die Async-Anfrage die Antwort verarbeitet und entweder einen Fehler anzeigt, falls vorhanden, oder machen Sie eine andere Operation mit dem Ergebnis.Wie bekomme ich die Antwort einer asynchronen Webanfrage von außerhalb der Methode?

Hier ist mein Code, ich die Anfrage hier anrufen und einige Daten in geben

private void SignInExecute() 
{ 

     if (Username == null || Password == null) 
     { 
      LoginOutput = "Please provide a username or password."; 
     } 
     else 
     { 
      this.webService.SendLoginRequest("http://localhost:3000/client_sessions", "username=" + Username + "&password=" + Password); 

     } 

} 

Und hier ist der eigentliche Code Web-Anfrage.

public void SendLoginRequest(string url, string postdata) 
{ 
     HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 

     request.Method = "POST"; 

     request.ContentType = "application/x-www-form-urlencoded"; 

     request.Accept = "application/json"; 

     byte[] byteArray = Encoding.UTF8.GetBytes(postdata); 

     request.CookieContainer = new CookieContainer(); 

     request.ContentLength = byteArray.Length; 

     Stream dataStream = request.GetRequestStream(); 

     dataStream.Write(byteArray, 0, byteArray.Length); 

     dataStream.Close(); 

     ((HttpWebRequest)request).KeepAlive = false; 

     request.BeginGetResponse(new AsyncCallback(GetLoginResponseCallback), request); 


    } 

    private static void GetLoginResponseCallback(IAsyncResult asynchronousResult) 
    { 
     HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState; 

     // End the operation 
     HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult); 
     Stream streamResponse = response.GetResponseStream(); 
     StreamReader streamRead = new StreamReader(streamResponse); 
     string responseString = streamRead.ReadToEnd(); 

     Console.WriteLine(responseString); 

     // Close the stream object 
     streamResponse.Close(); 
     streamRead.Close(); 
     response.Close(); 
    } 

So zu summieren. Ich möchte in der Lage sein, die Antwort an das Objekt zurückzugeben, das ursprünglich den Aufruf für die Webanforderung zum Starten gab. Irgendeine Hilfe?

+0

Winforms/Webformulare/Silverlight/was? –

+0

WPF, dachte nicht, dass es zu wichtig war hinzuzufügen. Die Tags wurden aktualisiert, um sie wiederzugeben. – benjgorman

Antwort

2

Sie müssen die BeginGetResponse anweisen, in denselben Kontext zurückzukehren, in dem sie über SynchronizationContext.Current aufgerufen wurde. So etwas (der Code hat keine korrekte Fehlerüberprüfung, also sollten Sie darüber nachdenken) (Außerdem ist Platinum Azure korrekt, dass Sie eine using verwenden sollten, damit Ihre Streams ordnungsgemäß (und garantiert) geschlossen werden können:

In Ihre SendLoginRequest:

//Box your object state with the current thread context 
object[] boxedItems = new []{request, SynchronizationContext.Current}; 
request.BeginGetResponse(new AsyncCallback(GetLoginResponseCallback), 
    boxedItems); 

Die GetResponse Code:

private static void GetLoginResponseCallback(IAsyncResult asynchronousResult) 
{ 
//MY UPDATE 
    //Unbox your object state with the current thread context 
    object[] boxedItems = asynchronousResult.AsyncState as object[]; 
    HttpWebRequest request = boxedItems[0] as HttpWebRequest; 
    SynchronizationContext context = boxedItems[1] as SynchronizationContext; 

    // End the operation 
    using(HttpWebResponse response = 
     (HttpWebResponse)request.EndGetResponse(asynchronousResult)) 
    { 
     using(Stream streamResponse = response.GetResponseStream()) 
     { 
      using(StreamReader streamRead = new StreamReader(streamResponse)) 
      { 
       string responseString = streamRead.ReadToEnd(); 

       Console.WriteLine(responseString); 
//MY UPDATE 
       //Make an asynchronous call back onto the main UI thread 
       //(context.Send for a synchronous call) 
       //Pass responseString as your method parameter 
       //If you have more than one object, you will have to box again 
       context.Post(UIMethodToCall, responseString); 
      } 
     } 
    } 
} 

Um Ihre UI Verarbeitung

public static void UIMethodCall(object ObjectState) 
{ 
    String response = ObjectState as String; 
    label1.Text = String.Format("Output: {0}", response); 
    //Or whatever you need to do in the UI... 
} 
01 zu implementieren

Nun würde ich das aber zuerst testen. Mein Verständnis von Microsofts Implementierung von ereignisgesteuertem Async war, dass die Antwort kontextbewusst war und wusste, in welchen Kontext ich zurückkehren sollte. Bevor Sie also zu der Annahme übergehen, dass Sie nicht im selben Kontext sind, testen Sie es, indem Sie versuchen, die Benutzeroberfläche zu aktualisieren (dies führt zu einer Threadkontextausnahme, wenn Sie nicht im aufrufenden (UI) -Thread sind)

+0

Sie sollten wahrscheinlich try/finally oder 'using' verwenden, um sicherzustellen, dass die Ressourcen im Falle einer Ausnahme ordnungsgemäß geschlossen werden. –

+0

@PlatinumAzure Ich habe den Code aktualisiert, da das besser ist, Sie haben Recht. Sie haben mich auch daran erinnert zu bemerken, dass der Code keine Fehlerprüfung hat. –

+0

Ich glaube, ich verstehe, was Sie geschrieben haben, abgesehen von der letzten Zeile context.Post (UIMethodToCall, StateObjectThatUIWillActOn); Könnten Sie das ein bisschen weiter vertiefen? – benjgorman

Verwandte Themen