Как я могу получить ответ на асинхронный веб-запрос извне метода? - PullRequest
4 голосов
/ 26 марта 2012

Я немного растерялся.Я пытаюсь опубликовать в своем веб-сервисе асинхронный способ, в идеале я хочу запустить запрос, показать спиннер загрузки в пользовательском интерфейсе, а затем, когда асинхронный запрос завершится, обработать ответ и либо показать ошибку, если она есть,или выполните другую операцию с результатом.

Вот мой код, я вызываю запрос и передаю некоторые данные.

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

        }

}

А вот фактический код веб-запроса:

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

Итак, подведем итоги.Я хочу иметь возможность вернуть ответ обратно на объект, который первоначально дал вызов для запуска веб-запроса.Любая помощь?

1 Ответ

2 голосов
/ 26 марта 2012

Вы должны указать BeginGetResponse, чтобы вернуться в тот же контекст, в котором он был вызван через SynchronizationContext.Current.Примерно так (код не имеет надлежащей проверки ошибок, поэтому вы должны правильно об этом подумать) (Кроме того, Platinum Azure правильно, что вы должны использовать using, чтобы ваши потоки закрывались правильно (и гарантировано):

В вашем SendLoginRequest:

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

Код getresponse:

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

Для реализации обработки вашего пользовательского интерфейса

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

Теперь я бы протестировал этоВо-первых, я понял, что Microsoft реализовала асинхронность, управляемую событиями, что ответ был контекстно-зависимым и знал, к какому контексту возвращаться.попытка обновить пользовательский интерфейс (это вызовет исключение контекста потока, если вы не находитесь в вызывающем потоке (UI))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...