.NET 实现异步请求

System.Net 类使用 .NET Framework 的标准异步编程模型对 Internet 资源进行异步访问。WebRequest 类的 BeginGetResponseEndGetResponse 方法分别启动和完成对 Internet 资源的异步请求。

Note注意 

在异步回调方法中使用同步调用可能会导致性能严重下降。通过 WebRequest 及其子代实现的 Internet 请求必须使用 Stream.BeginRead 读取由 WebResponse.GetResponseStream 方法返回的流。

下面的示例代码说明如何通过 WebRequest 类使用异步调用。该示例是一个控制台程序,它从命令行获得 URI,请求此 URI 处的资源,然后在从 Internet 接收数据的过程中将数据输出到控制台。

该程序定义了两个供自己使用的类:一个是 RequestState 类,它在异步调用间传递数据;另一个是 ClientGetAsync 类,它实现对 Internet 资源的异步请求。

RequestState 类在服务于请求的异步方法调用间保留请求的状态。在 RequestState 类中,有包含当前资源请求和收到的响应流的 WebRequest 和 Stream 实例、包含当前从 Internet 资源接收到的数据的缓冲区和包含整个响应的 StringBuilder。当 AsyncCallback 方法向 WebRequest.BeginGetResponse 注册时,RequestState 作为 state 参数传递。

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

  • allDone 属性包含 ManualResetEvent 类的一个实例,该实例发出信号表示请求已完成。

  • Main() 方法读取命令行并开始对指定 Internet 资源的请求。此方法创建 WebRequest wreq 和 RequestState rs,调用 BeginGetResponse 开始处理请求,然后调用 allDone.WaitOne() 方法,以使应用程序在回调完成后才退出。读取来自 Internet 资源的响应后,Main() 将响应写到控制台,然后应用程序结束。

  • showusage() 方法将示例命令行写到控制台。如果命令行中没有提供 URI,Main() 将调用此方法。

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

  • ReadCallBack() 方法实现读取响应流的异步回调方法。它将从 Internet 资源接收的数据传输到 RequestState 实例的 ResponseData 属性中,然后对响应流启动另一个异步读取,直到不再有数据返回为止。读取完所有数据后,ReadCallBack() 关闭响应流,并调用 allDone.Set() 方法以指示 ResponseData 中的响应是完整的。

Note注意

 

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(
" Usage:");
      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;
   }
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值