【问题标题】:Use HttpWebRequest with async and await将 HttpWebRequest 与 async 和 await 一起使用
【发布时间】:2015-04-28 13:03:37
【问题描述】:

我刚开始使用 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。 p>

初始化请求应该发回一个字符串,该字符串在 GetResponseStreamCallBack 中设置,但它似乎在最后两个方法执行之前发回了一个字符串。 Soo,我读到了 asyncawait 并且我尝试使用它们,但是 Visual Studio 说 Cannot await "method group" 我在哪里等待

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

}
}

非常感谢任何解决此问题的帮助,我希望 initialize_request() 执行,等待 GetRequestStreamCallbackGetResponseStreamCallback 完成,然后返回请求响应

[更新] 根据 cmets 部分,我被建议使用 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?"); 永远不会被执行!

【问题讨论】:

  • 您不需要异步的 GetRequestStreamCallback 方法。将其签名更改为 private void GetRequestStreamCallback(IAsyncResult callbackResult)
  • @VictorMukherjee 我试过了,但仍然是'Debug.WriteLine(“我们回来了吗?”);'在这两种方法中的任何一种之前执行!
  • 另外,如果你想使用异步模型,你会想使用 request.GetRequestStreamAsync。
  • Debug.WriteLine("我们回来了吗?");大多数情况下会在这两个方法之前执行,因为 request.BeginGetRequestStream 方法是异步执行的,但是由于它没有使用任何 async 关键字,所以不能等待任务。但是,您可以使用 AutoResetEvent 在 BeginGetRequestStream 之后等待 initialize_request 方法,并从 GetResponsetStreamCallback 设置 AutoResetEvent。
  • @VictorMukherjee 我已经尝试过 AutoRestEvent,请参阅更新后的问题!谢谢

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


【解决方案1】:

就像 Stephen Cleary 提到的那样,由于您正在为 Windows Phone 8 构建,请考虑使用 HttpClient 而不是 HttpWebRequest 类。这背后的原因不仅仅是“容易得多”。

正如 VS 论坛上所述:

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

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

  4. 您可以从HttpClient 派生来为特定站点或模式创建专门的客户端

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

如需了解更多信息,请阅读完整的post并参考此link

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

【讨论】:

  • 我将调查HttpClient 将提供反馈意见!不过,我会更感兴趣的是解决我当前情况的解决方案,然后是替代方案。
  • 我完全理解你的意思,只是我觉得使用过时的东西不太合适。检查:msdn.microsoft.com/en-us/library/cc190216%28v=vs.110%29.aspx
  • 我已经求助于HttpClient,它正在做这项工作,在几次尝试解决问题失败后,会将代码推送到 git-hub 并在此处分享链接。谢谢推荐
猜你喜欢
  • 2018-09-03
  • 1970-01-01
  • 2018-11-21
  • 2017-11-05
  • 2019-04-15
  • 2014-06-19
  • 2018-01-14
  • 2018-09-12
  • 1970-01-01
相关资源
最近更新 更多