简体   繁体   中英

Use HttpWebRequest with async and await

I just started using C# so forgive my ignorance(if any) of how i use it. I have a login button which executes the following code

private void Login_Click(object sender, RoutedEventArgs e)
    {
        if (email_box.Text != "" && password_box.Password != "") {
            string strRegex = @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +    @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +  @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
            Regex reg = new Regex(strRegex);
            if (reg.IsMatch(email_box.Text))
            {
                ApiCall request = new ApiCall();
                request.requestData = "{\"sessions\": {\"links\":{\"user\":{\"email\":\"" + email_box.Text + "\",\"password\":\"" + password_box.Password + "\" }}}}";
                request.requestMethod = Constants.httpMethods[0];
                request.resource_url = "/sessions";
                var response = request.initialize_request();       
                //Once i get the response string, i will deserialize it here and use it to do other things, like navigate to a new page an any other neccessary things to do!
            }
            else
            {
                recover.Text = "Please provide a valid email address.";
            } 
        }
        else
        {
            recover.Text = "Email and Password cannot be Empty";
        }
    }   

The method initializese this class and also calls the initialize_request() , which inturn calls the GetRequestStreamCallback which also calls the GetResponseStreamCallback .

Intialize request is supposed to send back a string, which is set in GetResponseStreamCallBack but it seems, it sends back a string before the last two methods have executed. Soo, i read about async and await and i have tried to use them, but the Visual Studio says Cannot await "method group" where i put the awaits

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Diagnostics;
using System.Net;
using Newtonsoft.Json;
using PrintMyPic.ApiJsonObjects;
using PrintMyPic;
using System.Windows.Navigation;

namespace MyApp
{
    class ApiCall
    {
        public static string api_url = "http://myappsapiurl/api";
        public static string content_type = "application/vnd.api+json";
        public string requestData; 
        public string requestMethod; 
        public string resource_url; // the rest of the api url 
        public string requestResponse;               
    public async Task<string> initialize_request()
    {
        Debug.WriteLine("the resource used is "+ resource_url);
        System.Uri myUri = new System.Uri(api_url+resource_url);
        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(myUri);
        request.ContentType = content_type;
        request.Method = requestMethod;
        request.Accept = content_type;
        request.BeginGetRequestStream(new AsyncCallback(await GetRequestStreamCallback), request);
        Debug.WriteLine("have we returned yet?");
       return requestResponse;
    }
    private async Task  GetRequestStreamCallback(IAsyncResult callbackResult)
    {
        Debug.WriteLine("we are in the second method");
        HttpWebRequest webrequest = (HttpWebRequest)callbackResult.AsyncState;
        Stream postStream = webrequest.EndGetRequestStream(callbackResult);           
        byte[] byteArray = Encoding.UTF8.GetBytes(requestData);
        postStream.Write(byteArray, 0, byteArray.Length);
        postStream.Close();
        webrequest.BeginGetResponse(new AsyncCallback( await GetResponsetStreamCallback), webrequest);
    }

    private void GetResponsetStreamCallback(IAsyncResult callbackResult)
    {
        Debug.WriteLine("we are in the third method");

        try
        {
            HttpWebRequest request = (HttpWebRequest)callbackResult.AsyncState;
            HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callbackResult);
            string responseString = "";
            Stream streamResponse = response.GetResponseStream();
            StreamReader reader = new StreamReader(streamResponse);
            responseString = reader.ReadToEnd();
            streamResponse.Close();
            reader.Close();
            response.Close();
            requestResponse = responseString;
        }
        catch (Exception e)
        {
            //show user-friendly error message as well as detailed one.
            //for better UI, consider using WPToolKit's CustomMessageBox to show these
            Debug.WriteLine("something wrong happened. \nDetails: " + e.HResult.ToString());
        }
    } 

}
}

Anyhelp fixing this is highly appreciated, i want intialize_request() to execute, wait for both GetRequestStreamCallback and GetResponseStreamCallback to finish, before returning the requestResponse

[Update] Based on the comments section, i have been advised to use AutoResetEvent

namespace MyApp
{
    class ApiCall
    {
        public static string api_url = "http://myappapirul/api";
        public static string content_type = "application/vnd.api+json";
        public string requestData; 
        public string requestMethod; 
        public string resource_url; // the rest of the api url 
        public string requestResponse;
        public static AutoResetEvent objAuto = new AutoResetEvent(false);       
    public string initialize_request()
    {
        Debug.WriteLine("the resource used is "+ resource_url);
        System.Uri myUri = new System.Uri(api_url+resource_url);
        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(myUri);
        request.ContentType = content_type;
        request.Method = requestMethod;
        request.Accept = content_type;
        request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
        objAuto.WaitOne();
        Debug.WriteLine("have we returned yet?");
        return requestResponse;

    }
    private void  GetRequestStreamCallback(IAsyncResult callbackResult)
    {
        Debug.WriteLine("we are in the second method");
        HttpWebRequest webrequest = (HttpWebRequest)callbackResult.AsyncState;
        Stream postStream = webrequest.EndGetRequestStream(callbackResult);           
        byte[] byteArray = Encoding.UTF8.GetBytes(requestData);
        postStream.Write(byteArray, 0, byteArray.Length);
        postStream.Close();
        webrequest.BeginGetResponse(new AsyncCallback(GetResponsetStreamCallback), webrequest);

    }

    private void GetResponsetStreamCallback(IAsyncResult callbackResult)
    {
        Debug.WriteLine("we are in the third method");

        try
        {
            HttpWebRequest request = (HttpWebRequest)callbackResult.AsyncState;
            HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callbackResult);
            string responseString = "";
            Stream streamResponse = response.GetResponseStream();
            StreamReader reader = new StreamReader(streamResponse);
            responseString = reader.ReadToEnd();
            streamResponse.Close();
            reader.Close();
            response.Close();
            requestResponse = responseString;

        }
        catch (Exception e)
        {
            //show user-friendly error message as well as detailed one.
            //for better UI, consider using WPToolKit's CustomMessageBox to show these
            Debug.WriteLine("something wrong happened. \nDetails: " + e.HResult.ToString());
        }
        Debug.WriteLine("we are about to return to initialize_request");
        objAuto.Set();
    } 

}
}

Problem now is, GetResponsetStreamCallback never starts, and it looks like i never return, because Debug.WriteLine("have we returned yet?"); never gets executed!

Like Stephen Cleary mentioned and since you are building for Windows Phone 8 please consider using HttpClient instead of HttpWebRequest class. The reasons behind this is not just that is "a lot easier".

As mentioned on VS forums:

HttpClient is more like a head-less browser. It a powerfull and ideal tool if you are going to be creating many http request. For example you can set default headers and stuff. Here are the top 5 ways it differs from an HttpWebRequest :

  1. An HttpClient instance is the place to configure extensions, set default headers, cancel outstanding requests and more.
  2. You can issue as many requests as you like through a single HttpClient instance.
  3. HttpClients are not tied to particular HTTP server or host; you can submit any HTTP request using the same HttpClient instance.

  4. You can derive from HttpClient to create specialized clients for particular sites or patterns

  5. HttpClient uses the new Task-oriented pattern for handling asynchronous requests making it dramatically easier to manage and coordinate multiple outstanding requests.

For more information, please read the whole post and refer to this link .

There are several examples and complete projects showing how to use HttpClient in different ways and not just to load string but to create c# objects from JSON objects as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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