简体   繁体   English

我实际上如何从方法外部获取异步Web请求的响应?

[英]How do I actually get the response of an async web request from outside the method?

I'm a little confused. 我有点困惑。 I'm trying to post to my web service in an async manner, ideally I want to start the request, show a loading spinner on the UI and then when the async request finishes process the response and either show an error if there is one, or do another operation with the result. 我正在尝试以异步方式发布到我的Web服务,理想情况下,我想启动请求,在UI上显示一个加载微调器,然后在异步请求完成后处理响应,如果有一个,则显示错误,或对结果进行其他操作。

Here is my code, I call the request here and pass some data in. 这是我的代码,我在这里调用请求并传递一些数据。

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

        }

}

And here is the actual web request code: 这是实际的Web请求代码:

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 to sum up. 综上所述。 I want to be able to return the response back to the object which originally gave the call for the web request to start. 我希望能够将响应返回到最初发出调用以启动Web请求的对象。 Any help? 有什么帮助吗?

You need to tell the BeginGetResponse to go back to the same context in which it was called via SynchronizationContext.Current . 您需要告诉BeginGetResponse返回到通过SynchronizationContext.Current调用的上下文。 Something like this (the code does not have proper error checking, so you should think about that properly) (Also, Platinum Azure is correct that you should use a using to let your streams close properly (and guaranteed): 这样的事情(代码没有正确的错误检查,因此您应该考虑正确)(此外,Platinum Azure是正确的,您应该使用using来让您的流正确关闭(并保证):

In your SendLoginRequest: 在您的SendLoginRequest中:

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

The getresponse code: 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);
            }
        }
    }
}

To implement your UI processing 实施UI处理

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

Now, I would test this out first, though. 现在,我将首先进行测试。 My understanding of Microsoft's implementation of event driven async was that the response was context-aware, and knew which context to return to. 我对Microsoft实现的事件驱动异步的理解是,响应是上下文感知的,并且知道要返回到哪个上下文。 So, before jumping to the assumption that you are not on the same context, test it out by trying to update the UI (this will cause a thread context exception if you are not on the calling (UI) thread) 因此,在跳到您不在同一个上下文的假设之前,请尝试通过尝试更新UI进行测试(如果您不在调用(UI)线程上,这将导致线程上下文异常)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM