C#:使用超时下载URL

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

编辑:经过很长一段时间使用WebRequest ,我发现了自定义WebClient 。 好多了。

同步方式:

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

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

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

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

我们创建了一个具有超时支持的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(); } } 

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