C# Can';尝试使用WebClient.DownloadFile()或WebRequest下载文件时无法实现超时
我正在尝试实现一些从URL下载文件的功能。但是,如果文件占用的时间超过30秒,我想取消下载,或者让它超时 我已经尝试重写WebClient类来实现超时,但是无论我将超时设置为什么值,它都不会超时!这是我试过的代码:C# Can';尝试使用WebClient.DownloadFile()或WebRequest下载文件时无法实现超时,c#,.net,asp.net-mvc-4,C#,.net,Asp.net Mvc 4,我正在尝试实现一些从URL下载文件的功能。但是,如果文件占用的时间超过30秒,我想取消下载,或者让它超时 我已经尝试重写WebClient类来实现超时,但是无论我将超时设置为什么值,它都不会超时!这是我试过的代码: 我还尝试使用WebRequest方法下载文件,并使用Timeout和ReadWriteTimeout属性,但没有骰子。这必须是一个非常常见的用例。感谢您的帮助。谢谢 您实现的超时与获取响应有关,但与包含所有数据的ResponseStream无关,通常需要更多时间才能实现。例如,获取响
我还尝试使用WebRequest方法下载文件,并使用Timeout和ReadWriteTimeout属性,但没有骰子。这必须是一个非常常见的用例。感谢您的帮助。谢谢 您实现的超时与获取响应有关,但与包含所有数据的ResponseStream无关,通常需要更多时间才能实现。例如,获取响应通常需要不到1秒的时间,但下载网页内容可能需要几秒钟 至于下载文件,您可以使用
HttpWebRequest
获取HttpWebResponse
并从中使用方法GetResponseStream()
获取数据流
这将有助于:
尤其是byte[]buffer
用于获取部分数据的部分,而不是StreamReader
ReadToEnd()
方法。在将部分数据下载到缓冲区时,您可以根据超时日期时间检查当前日期时间,从而允许在超时日期时间之后取消下载
编辑:一段有用的代码
private byte[] DownloadFile( string uri, int requestTimeout, int downloadTimeout, out bool isTimeout, out int bytesDownloaded )
{
HttpWebRequest request = WebRequest.Create( uri ) as HttpWebRequest;
request.Timeout = requestTimeout;
HttpWebResponse response = null;
Stream responseStream = null;
MemoryStream downloadedData = null;
byte[] result = null;
bytesDownloaded = 0;
isTimeout = false;
try
{
// Get response
response = request.GetResponse() as HttpWebResponse;
byte[] buffer = new byte[ 16384 ];
// Create buffer for downloaded data
downloadedData = new MemoryStream();
// Set the timeout
DateTime timeout = DateTime.Now.Add( new TimeSpan( 0, 0, 0, 0, downloadTimeout ) );
// Read parts of the stream
responseStream = response.GetResponseStream();
int bytesRead = 0;
DateTime now = DateTime.Now;
while ( (bytesRead = responseStream.Read( buffer, 0, buffer.Length )) > 0 && DateTime.Now < timeout )
{
downloadedData.Write( buffer, 0, bytesRead );
now = DateTime.Now;
bytesDownloaded += bytesRead;
}
// Notify if timeout occured (could've been written better)
if ( DateTime.Now >= timeout )
{
isTimeout = true;
}
}
catch ( WebException ex )
{
// Grab timeout exception
if ( ex.Status == WebExceptionStatus.Timeout )
{
isTimeout = true;
}
}
finally
{
// Close the stream
if ( responseStream != null )
{
responseStream.Close();
}
}
if ( downloadedData != null )
{
result = downloadedData.GetBuffer();
downloadedData.Close();
}
return result;
}
记住,对于您可能遇到的其他异常,此代码仍然容易受到攻击。创建扩展方法如何
WebClient wc = new WebClient();
wc.DownloadFileWithTimeout(url, filename, 20000);
公共静态类SOExtensions
{
public static void DownloadFileWithTimeout(此WebClient wc、字符串url、字符串文件、int timeout)
{
var tcs=new TaskCompletionSource();
var bgTask=Task.Factory.StartNew(()=>
{
DownloadFileTaskAsync(url,file).Wait();
tcs.TrySetResult(真);
});
如果(!bgTask.Wait(超时))
{
wc.CancelAsync();
抛出新的TimeoutException(“下载\'+url+“\””时超时);
}
}
}
我尝试了你的代码,没有发现任何问题。正如您所期望的那样超时。我在HttpWebRequest上单独使用超时时遇到了各种问题,因为它没有涵盖有关下载实际数据的超时。OP的代码在我的机器上也不能正常工作。它尝试下载整个文件(测试下载6MB文件时超时为500ms,OP的方法下载需要1800ms)。
private byte[] DownloadFile( string uri, int requestTimeout, int downloadTimeout, out bool isTimeout, out int bytesDownloaded )
{
HttpWebRequest request = WebRequest.Create( uri ) as HttpWebRequest;
request.Timeout = requestTimeout;
HttpWebResponse response = null;
Stream responseStream = null;
MemoryStream downloadedData = null;
byte[] result = null;
bytesDownloaded = 0;
isTimeout = false;
try
{
// Get response
response = request.GetResponse() as HttpWebResponse;
byte[] buffer = new byte[ 16384 ];
// Create buffer for downloaded data
downloadedData = new MemoryStream();
// Set the timeout
DateTime timeout = DateTime.Now.Add( new TimeSpan( 0, 0, 0, 0, downloadTimeout ) );
// Read parts of the stream
responseStream = response.GetResponseStream();
int bytesRead = 0;
DateTime now = DateTime.Now;
while ( (bytesRead = responseStream.Read( buffer, 0, buffer.Length )) > 0 && DateTime.Now < timeout )
{
downloadedData.Write( buffer, 0, bytesRead );
now = DateTime.Now;
bytesDownloaded += bytesRead;
}
// Notify if timeout occured (could've been written better)
if ( DateTime.Now >= timeout )
{
isTimeout = true;
}
}
catch ( WebException ex )
{
// Grab timeout exception
if ( ex.Status == WebExceptionStatus.Timeout )
{
isTimeout = true;
}
}
finally
{
// Close the stream
if ( responseStream != null )
{
responseStream.Close();
}
}
if ( downloadedData != null )
{
result = downloadedData.GetBuffer();
downloadedData.Close();
}
return result;
}
private void button1_Click( object sender, EventArgs e )
{
bool isTimeout;
int bytesDownloaded;
byte[] data = DownloadFile( something, 1000,500, out isTimeout, out bytesDownloaded );
MessageBox.Show( "Downloaded " + bytesDownloaded.ToString() + " bytes, Timeout = " + isTimeout.ToString() );
}
WebClient wc = new WebClient();
wc.DownloadFileWithTimeout(url, filename, 20000);
public static class SOExtensions
{
public static void DownloadFileWithTimeout(this WebClient wc, string url, string file, int timeout)
{
var tcs = new TaskCompletionSource<bool>();
var bgTask = Task.Factory.StartNew(() =>
{
wc.DownloadFileTaskAsync(url, file).Wait();
tcs.TrySetResult(true);
});
if (!bgTask.Wait(timeout))
{
wc.CancelAsync();
throw new TimeoutException("Timed out while downloading \"" + url + "\"");
}
}
}