C# 实现 HttpWebRequest 异步调用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12281777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 22:44:36  来源:igfitidea点击:

Implementing HttpWebRequest Async calls

c#asynchronoushttpwebrequeststreamwriter

提问by Sachin Kainth

I have this code

我有这个代码

using (var stream = new StreamWriter(request.GetRequestStream(), Encoding))
   stream.Write(body.ToString());

I need to make it asynchronous. As far as I understand it, this means I need to change the call to request.GetRequestStream()to the asychronous.BeginGetRequestStream(). I have seen thisexample but cannot figure out how to apply that to this scenario. Can someone help?

我需要使它异步。据我了解,这意味着我需要将调用更改request.GetRequestStream()asychronous.BeginGetRequestStream(). 我看过这个例子,但不知道如何将它应用到这个场景中。有人可以帮忙吗?

采纳答案by exacerbatedexpert

The documentation has a good example (http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetrequeststream(v=vs.100).aspx):

该文档有一个很好的例子(http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetrequeststream(v=vs.100).aspx):

using System;
using System.Net;
using System.IO;
using System.Text;
using System.Threading;

class HttpWebRequestBeginGetRequest
{
    private static ManualResetEvent allDone = new ManualResetEvent(false);
public static void Main(string[] args)
{
    // Create a new HttpWebRequest object.
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.contoso.com/example.aspx");

    request.ContentType = "application/x-www-form-urlencoded";

    // Set the Method property to 'POST' to post data to the URI.
    request.Method = "POST";

    // start the asynchronous operation
    request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);

    // Keep the main thread from continuing while the asynchronous 
    // operation completes. A real world application 
    // could do something useful such as updating its user interface. 
    allDone.WaitOne();
}

private static void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
    HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;

    // End the operation
    Stream postStream = request.EndGetRequestStream(asynchronousResult);

    Console.WriteLine("Please enter the input data to be posted:");
    string postData = Console.ReadLine();

    // Convert the string into a byte array. 
    byte[] byteArray = Encoding.UTF8.GetBytes(postData);

    // Write to the request stream.
    postStream.Write(byteArray, 0, postData.Length);
    postStream.Close();

    // Start the asynchronous operation to get the response
    request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}

private static void GetResponseCallback(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();

    // Release the HttpWebResponse
    response.Close();
    allDone.Set();
}

回答by TechnicalKalsa

you can understand by this code.

你可以通过这段代码理解。

The program defines two classes for its own use, the RequestState class, which passes data across asynchronous calls, and the ClientGetAsync class, which implements the asynchronous request to an Internet resource.

该程序定义了两个类供自己使用,RequestState 类,它通过异步调用传递数据,以及 ClientGetAsync 类,它实现对 Internet 资源的异步请求。

The RequestState class preserves the state of the request across calls to the asynchronous methods that service the request. It contains WebRequest and Stream instances that contain the current request to the resource and the stream received in response, a buffer that contains the data currently received from the Internet resource, and a StringBuilder that contains the complete response. A RequestStateis passed as the state parameter when the AsyncCallback method is registered with WebRequest.BeginGetResponse.

RequestState 类通过调用为请求提供服务的异步方法来保留请求的状态。它包含 WebRequest 和 Stream 实例,其中包含对资源的当前请求和响应中接收到的流,一个包含当前从 Internet 资源接收到的数据的缓冲区,以及一个包含完整响应的 StringBuilder。当使用 WebRequest.BeginGetResponse 注册 AsyncCallback 方法时,RequestState 作为状态参数传递。

The ClientGetAsync class implements an asynchronous request to an Internet resource and writes the resulting response to the console. It contains the methods and properties described in the following list.

ClientGetAsync 类实现对 Internet 资源的异步请求,并将结果响应写入控制台。它包含以下列表中描述的方法和属性。

The allDone property contains an instance of the ManualResetEvent class that signals the completion of the request.

allDone 属性包含一个 ManualResetEvent 类的实例,它表示请求的完成。

The Main() method reads the command line and begins the request for the specified Internet resource. It creates the WebRequest wreq and the RequestState rs, calls BeginGetResponse to begin processing the request, and then calls the allDone.WaitOne()method so that the application will not exit until the callback is complete. After the response is read from the Internet resource, Main() writes it to the console and the application ends.

Main() 方法读取命令行并开始请求指定的 Internet 资源。它创建 WebRequest wreq 和 RequestState rs,调用 BeginGetResponse 开始处理请求,然后调用 allDone.WaitOne() 方法,这样应用程序在回调完成之前不会退出。从 Internet 资源读取响应后, Main() 将其写入控制台,应用程序结束。

The showusage() method writes an example command line on the console. It is called by Main() when no URI is provided on the command line.

showusage() 方法在控制台上编写示例命令行。当命令行上没有提供 URI 时,它由 Main() 调用。

The RespCallBack() method implements the asynchronous callback method for the Internet request. It creates the WebResponse instance containing the response from the Internet resource, gets the response stream, and then starts reading the data from the stream asynchronously.

RespCallBack() 方法实现了 Internet 请求的异步回调方法。它创建包含来自 Internet 资源的响应的 WebResponse 实例,获取响应流,然后开始从流中异步读取数据。

The ReadCallBack() method implements the asynchronous callback method for reading the response stream. It transfers data received from the Internet resource into the ResponseData property of the RequestState instance, then starts another asynchronous read of the response stream until no more data is returned. Once all the data has been read, ReadCallBack() closes the response stream and calls the allDone.Set() method to indicate that the entire response is present in ResponseData.

ReadCallBack() 方法实现了读取响应流的异步回调方法。它将从 Internet 资源接收到的数据传输到 RequestState 实例的 ResponseData 属性,然后开始另一个异步读取响应流,直到没有更多数据返回。一旦读取了所有数据,ReadCallBack() 将关闭响应流并调用 allDone.Set() 方法以指示整个响应存在于 ResponseData 中。

using System;
using System.Net;
using System.Threading;
using System.Text;
using System.IO;

// The RequestState class passes data across async calls.
public class RequestState
{
   const int BufferSize = 1024;
   public StringBuilder RequestData;
   public byte[] BufferRead;
   public WebRequest Request;
   public Stream ResponseStream;
   // Create Decoder for appropriate enconding type.
   public Decoder StreamDecode = Encoding.UTF8.GetDecoder();

   public RequestState()
   {
      BufferRead = new byte[BufferSize];
      RequestData = new StringBuilder(String.Empty);
      Request = null;
      ResponseStream = null;
   }     
}

// ClientGetAsync issues the async request.
class ClientGetAsync 
{
   public static ManualResetEvent allDone = new ManualResetEvent(false);
   const int BUFFER_SIZE = 1024;

   public static void Main(string[] args) 
   {
      if (args.Length < 1) 
      {
         showusage();
         return;
      }

      // Get the URI from the command line.
      Uri httpSite = new Uri(args[0]);

      // Create the request object.
      WebRequest wreq = WebRequest.Create(httpSite);

      // Create the state object.
      RequestState rs = new RequestState();

      // Put the request into the state object so it can be passed around.
      rs.Request = wreq;

      // Issue the async request.
      IAsyncResult r = (IAsyncResult) wreq.BeginGetResponse(
         new AsyncCallback(RespCallback), rs);

      // Wait until the ManualResetEvent is set so that the application 
      // does not exit until after the callback is called.
      allDone.WaitOne();

      Console.WriteLine(rs.RequestData.ToString());
   }

   public static void showusage() {
      Console.WriteLine("Attempts to GET a URL");
      Console.WriteLine("\r\nUsage:");
      Console.WriteLine("   ClientGetAsync URL");
      Console.WriteLine("   Example:");
      Console.WriteLine("      ClientGetAsync http://www.contoso.com/");
   }

   private static void RespCallback(IAsyncResult ar)
   {
      // Get the RequestState object from the async result.
      RequestState rs = (RequestState) ar.AsyncState;

      // Get the WebRequest from RequestState.
      WebRequest req = rs.Request;

      // Call EndGetResponse, which produces the WebResponse object
      //  that came from the request issued above.
      WebResponse resp = req.EndGetResponse(ar);         

      //  Start reading data from the response stream.
      Stream ResponseStream = resp.GetResponseStream();

      // Store the response stream in RequestState to read 
      // the stream asynchronously.
      rs.ResponseStream = ResponseStream;

      //  Pass rs.BufferRead to BeginRead. Read data into rs.BufferRead
      IAsyncResult iarRead = ResponseStream.BeginRead(rs.BufferRead, 0, 
         BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs); 
   }


   private static void ReadCallBack(IAsyncResult asyncResult)
   {
      // Get the RequestState object from AsyncResult.
      RequestState rs = (RequestState)asyncResult.AsyncState;

      // Retrieve the ResponseStream that was set in RespCallback. 
      Stream responseStream = rs.ResponseStream;

      // Read rs.BufferRead to verify that it contains data. 
      int read = responseStream.EndRead( asyncResult );
      if (read > 0)
      {
         // Prepare a Char array buffer for converting to Unicode.
         Char[] charBuffer = new Char[BUFFER_SIZE];

         // Convert byte stream to Char array and then to String.
         // len contains the number of characters converted to Unicode.
      int len = 
         rs.StreamDecode.GetChars(rs.BufferRead, 0, read, charBuffer, 0);

         String str = new String(charBuffer, 0, len);

         // Append the recently read data to the RequestData stringbuilder
         // object contained in RequestState.
         rs.RequestData.Append(
            Encoding.ASCII.GetString(rs.BufferRead, 0, read));         

         // Continue reading data until 
         // responseStream.EndRead returns –1.
         IAsyncResult ar = responseStream.BeginRead( 
            rs.BufferRead, 0, BUFFER_SIZE, 
            new AsyncCallback(ReadCallBack), rs);
      }
      else
      {
         if(rs.RequestData.Length>0)
         {
            //  Display data to the console.
            string strContent;                  
            strContent = rs.RequestData.ToString();
         }
         // Close down the response stream.
         responseStream.Close();         
         // Set the ManualResetEvent so the main thread can exit.
         allDone.Set();                           
      }
      return;
   }    
}