【问题标题】:C#: Downloading a URL with timeoutC#:下载超时的 URL
【发布时间】:2008-11-17 13:21:58
【问题描述】:

在 .NET 中最好的方法是什么? 我总是忘记Dispose() 需要什么(或用using 包装)。

编辑:在长时间使用WebRequest 之后,我发现了自定义WebClient。好多了。

【问题讨论】:

    标签: c# httpwebrequest timeout webrequest .net-3.0


    【解决方案1】:

    同步方式:

    var request = HttpWebRequest.Create("http://www.contoso.com");
    request.Timeout = 50000;
    using (var response = request.GetResponse())
    {
        //your code here
    }
    

    你也可以有异步的方式:

    using System;
    using System.Net;
    using System.IO;
    using System.Text;
    using System.Threading;
    
    
    public class RequestState
    {
      // This class stores the State of the request.
      const int BUFFER_SIZE = 1024;
      public StringBuilder requestData;
      public byte[] BufferRead;
      public HttpWebRequest request;
      public HttpWebResponse response;
      public Stream streamResponse;
      public RequestState()
      {
        BufferRead = new byte[BUFFER_SIZE];
        requestData = new StringBuilder("");
        request = null;
        streamResponse = null;
      }
    }
    
    class HttpWebRequest_BeginGetResponse
    {
        public static ManualResetEvent allDone = new ManualResetEvent(false);
        const int BUFFER_SIZE = 1024;
        const int DefaultTimeout = 2 * 60 * 1000; // 2 minutes timeout
    
        // Abort the request if the timer fires.
        private static void TimeoutCallback(object state, bool timedOut)
        {
            if (timedOut)
            {
                HttpWebRequest request = state as HttpWebRequest;
                if (request != null)
                {
                    request.Abort();
                }
            }
        }
    
        static void Main()
        {
    
            try
            {
                // Create a HttpWebrequest object to the desired URL. 
                HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create("http://www.contoso.com");
                myHttpWebRequest.ReadWriteTimeout = DefaultTimeout;
    
    
                // Create an instance of the RequestState and assign the previous myHttpWebRequest
                // object to its request field.  
                RequestState myRequestState = new RequestState();
                myRequestState.request = myHttpWebRequest;
    
    
                // Start the asynchronous request.
                IAsyncResult result =
                  (IAsyncResult)myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback), myRequestState);
    
                // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
                ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), myHttpWebRequest, DefaultTimeout, true);
    
                // The response came in the allowed time. The work processing will happen in the 
                // callback function.
                allDone.WaitOne();
    
                // Release the HttpWebResponse resource.
                myRequestState.response.Close();
            }
            catch (WebException e)
            {
                Console.WriteLine("\nMain Exception raised!");
                Console.WriteLine("\nMessage:{0}", e.Message);
                Console.WriteLine("\nStatus:{0}", e.Status);
                Console.WriteLine("Press any key to continue..........");
            }
            catch (Exception e)
            {
                Console.WriteLine("\nMain Exception raised!");
                Console.WriteLine("Source :{0} ", e.Source);
                Console.WriteLine("Message :{0} ", e.Message);
                Console.WriteLine("Press any key to continue..........");
                Console.Read();
            }
        }
        private static void RespCallback(IAsyncResult asynchronousResult)
        {
            try
            {
                // State of request is asynchronous.
                RequestState myRequestState = (RequestState)asynchronousResult.AsyncState;
                HttpWebRequest myHttpWebRequest = myRequestState.request;
                myRequestState.response = (HttpWebResponse)myHttpWebRequest.EndGetResponse(asynchronousResult);
    
                // Read the response into a Stream object.
                Stream responseStream = myRequestState.response.GetResponseStream();
                myRequestState.streamResponse = responseStream;
    
                // Begin the Reading of the contents of the HTML page and print it to the console.
                IAsyncResult asynchronousInputRead = responseStream.BeginRead(myRequestState.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), myRequestState);
                return;
            }
            catch (WebException e)
            {
                Console.WriteLine("\nRespCallback Exception raised!");
                Console.WriteLine("\nMessage:{0}", e.Message);
                Console.WriteLine("\nStatus:{0}", e.Status);
            }
            allDone.Set();
        }
        private static void ReadCallBack(IAsyncResult asyncResult)
        {
            try
            {
    
                RequestState myRequestState = (RequestState)asyncResult.AsyncState;
                Stream responseStream = myRequestState.streamResponse;
                int read = responseStream.EndRead(asyncResult);
                // Read the HTML page and then print it to the console.
                if (read > 0)
                {
                    myRequestState.requestData.Append(Encoding.ASCII.GetString(myRequestState.BufferRead, 0, read));
                    IAsyncResult asynchronousResult = responseStream.BeginRead(myRequestState.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), myRequestState);
                    return;
                }
                else
                {
                    Console.WriteLine("\nThe contents of the Html page are : ");
                    if (myRequestState.requestData.Length > 1)
                    {
                        string stringContent;
                        stringContent = myRequestState.requestData.ToString();
                        Console.WriteLine(stringContent);
                    }
                    Console.WriteLine("Press any key to continue..........");
                    Console.ReadLine();
    
                    responseStream.Close();
                }
    
            }
            catch (WebException e)
            {
                Console.WriteLine("\nReadCallBack Exception raised!");
                Console.WriteLine("\nMessage:{0}", e.Message);
                Console.WriteLine("\nStatus:{0}", e.Status);
            }
            allDone.Set();
    
        }
    }
    

    【讨论】:

      【解决方案2】:

      这是我使用的,它似乎可以工作,但我不知道这是不是最好的方法:

      public string GetRequest(Uri uri, int timeoutMilliseconds)
      {
          var request = System.Net.WebRequest.Create(uri);
          request.Timeout = timeoutMilliseconds;
          using (var response = request.GetResponse())
          using (var stream = response.GetResponseStream())
          using (var reader = new System.IO.StreamReader(stream))
          {
              return reader.ReadToEnd();
          }
      }
      

      【讨论】:

      • 对于不需要发送 POST 变量的简单 url 来说还不错。您应该标记您使用 Framework 3.5...
      • 我只对生产代码使用异步请求。在我的回答中,您可以找到我从 MSDN 克隆的巨大异步代​​码,并添加了 myHttpWebRequest.ReadWriteTimeout = DefaultTimeout; 这一行
      • @Vernicht - 谢谢!我一直在寻找非常简单的阻塞(同步)下载,但欢迎使用异步代码示例!
      【解决方案3】:

      根据 Thomas Levesque 的评论 here,有一个更简单、更通用的解决方案。

      我们创建了一个支持超时的WebClient 子类,我们得到了WebClient 的所有优点。

      public class WebClientWithTimeout : WebClient
      {
        private readonly int timeoutMilliseconds;
        public WebClientWithTimeout(int timeoutMilliseconds)
        {
          this.timeoutMilliseconds = timeoutMilliseconds;
        }
      
        protected override WebRequest GetWebRequest(Uri address)
        {
          var result = base.GetWebRequest(address);
          result.Timeout = timeoutMilliseconds;
          return result;
        }
      }
      

      示例用法:

      public string GetRequest(Uri uri, int timeoutMilliseconds)
      {
        using (var client = new WebClientWithTimeout(timeoutMilliseconds))
        {
          return client.DownloadString();
        }
      }
      

      【讨论】:

        【解决方案4】:

        在单独的线程中运行 System.Net.WebClient,设置一个计时器以在您的最大时间后终止它。

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-10
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多