将HttpWebRequest与async和await一起使用

时间:2015-04-27 10:05:56

标签: c# windows-phone-8 httpwebrequest async-await

我刚开始使用C#,请原谅我如何使用它的无知(如果有的话)。 我有一个登录按钮,执行以下代码

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

该方法初始化此类并调用 initialize_request(),其内部调用 GetRequestStreamCallback ,它也调用 GetResponseStreamCallback

Intialize请求应该发回一个字符串,该字符串在 GetResponseStreamCallBack 中设置但看起来,它在最后两个方法执行之前发回一个字符串。 Soo,我读到了异步等待,我试图使用它们,但Visual Studio说无法等待&#34;方法组&#34; < / strong>我把等待

    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修复此问题非常感谢,我希望 intialize_request()执行,等待 GetRequestStreamCallback GetResponseStreamCallback 完成,然后返回 requestResponse

[更新] 根据评论部分,我被建议使用 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();
    } 

}
}

现在的问题是, GetResponsetStreamCallback 永远不会启动,看起来我永远不会回来,因为Debug.WriteLine("have we returned yet?");永远不会被执行!

1 个答案:

答案 0 :(得分:1)

就像Stephen Cleary所提到的那样,既然您正在为Windows Phone 8构建,请考虑使用HttpClient而不是HttpWebRequest类。这背后的原因不仅仅是这样,而且更容易&#34;。

如VS论坛所述:

  

HttpClient更像是无头浏览器。它是一个强大的和   如果您要创建许多http请求,这是理想的工具。对于   例如,您可以设置默认标题和内容。以下是前5种方式   它与HttpWebRequest

不同      
      
  1. HttpClient实例是配置扩展名的地方   默认标题,取消未完成的请求等。
  2.   
  3. 您可以通过单个HttpClient实例发出任意数量的请求。
  4.   
  5. HttpClients不依赖于特定的HTTP服务器或主机;您可以使用相同的HttpClient实例提交任何HTTP请求。

  6.   
  7. 您可以从HttpClient派生,为特定网站或模式创建专门的客户

  8.   
  9. HttpClient使用新的面向任务的模式来处理异步请求,使其更易于管理和管理   协调多个未完成的请求。
  10.   

有关详细信息,请阅读整个post并参阅此link

有几个示例和完整项目展示了如何以不同方式使用HttpClient,而不仅仅是加载字符串,还要从JSON对象创建c#对象。