简体   繁体   English

将HttpWebRequest与async一起使用并等待

[英]Use HttpWebRequest with async and await

I just started using C# so forgive my ignorance(if any) of how i use it. 我刚开始使用C#,因此请原谅我对使用它的了解(如果有的话)。 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 . 该方法初始化该类,还调用initialize_request() ,后者继而调用GetRequestStreamCallback ,后者又调用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. 初始化请求应该发送回一个字符串,该字符串是在GetResponseStreamCallBack中设置的,但是看起来,它在执行最后两个方法之前发送回了一个字符串。 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 洙,我读到异步等待 ,我曾试图使用它们,但在Visual Studio说, 不能等待在那里我把等待着 “法团”

    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 修复此问题的任何帮助都受到高度赞赏,我要执行intialize_request () ,等待GetRequestStreamCallbackGetResponseStreamCallback完成,然后再返回requestResponse

[Update] Based on the comments section, i have been advised to use AutoResetEvent [更新]根据评论部分,建议我使用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?"); 现在的问题是, GetResponsetStreamCallback永远不会启动,而且看起来我永远也不会返回,因为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. 就像Stephen Cleary提到的那样,由于您正在为Windows Phone 8进行构建,请考虑使用HttpClient而不是HttpWebRequest类。 The reasons behind this is not just that is "a lot easier". 这背后的原因不仅是“容易得多”。

As mentioned on VS forums: 如VS论坛所述:

HttpClient is more like a head-less browser. HttpClient更像是无头浏览器。 It a powerfull and ideal tool if you are going to be creating many http request. 如果您要创建许多http请求,它是一个功能强大且理想的工具。 For example you can set default headers and stuff. 例如,您可以设置默认标题和内容。 Here are the top 5 ways it differs from an HttpWebRequest : 以下是与HttpWebRequest不同的5种主要方式:

  1. An HttpClient instance is the place to configure extensions, set default headers, cancel outstanding requests and more. HttpClient实例是配置扩展,设置默认标头,取消未完成的请求等的地方。
  2. You can issue as many requests as you like through a single HttpClient instance. 您可以通过一个HttpClient实例发出任意多个请求。
  3. HttpClients are not tied to particular HTTP server or host; HttpClient不绑定到特定的HTTP服务器或主机。 you can submit any HTTP request using the same HttpClient instance. 您可以使用相同的HttpClient实例提交任何HTTP请求。

  4. You can derive from HttpClient to create specialized clients for particular sites or patterns 您可以从HttpClient派生来为特定站点或模式创建专门的客户端

  5. HttpClient uses the new Task-oriented pattern for handling asynchronous requests making it dramatically easier to manage and coordinate multiple outstanding requests. HttpClient使用面向任务的新模式来处理异步请求,从而大大简化了管理和协调多个未完成请求的过程。

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. 有几个示例和完整的项目显示了如何以不同方式使用HttpClient ,不仅可以加载字符串,还可以从JSON对象创建c#对象。

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

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