C# 如何更改 .NET WebClient 对象的超时时间
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1789627/
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
How to change the timeout on a .NET WebClient object
提问by Ryall
I am trying to download a client's data to my local machine (programatically) and their webserver is very, very slow which is causing a timeout in my WebClient
object.
我正在尝试将客户端的数据下载到我的本地机器(以编程方式),并且他们的网络服务器非常非常慢,这导致我的WebClient
对象超时。
Here is my code:
这是我的代码:
WebClient webClient = new WebClient();
webClient.Encoding = Encoding.UTF8;
webClient.DownloadFile(downloadUrl, downloadFile);
Is there a way to set an infinite timeout on this object? Or if not can anyone help me with an example on an alternate way to do this?
有没有办法在这个对象上设置无限超时?或者,如果没有,任何人都可以帮助我举一个替代方法的例子吗?
The URL works fine in a browser - it just takes about 3 minutes to show.
该 URL 在浏览器中运行良好 - 显示只需大约 3 分钟。
采纳答案by kisp
You can extend the timeout: inherit the original WebClient class and override the webrequest getter to set your own timeout, like in the following example.
您可以扩展超时:继承原始 WebClient 类并覆盖 webrequest getter 以设置您自己的超时,如下例所示。
MyWebClient was a private class in my case:
在我的例子中,MyWebClient 是一个私有类:
private class MyWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest w = base.GetWebRequest(uri);
w.Timeout = 20 * 60 * 1000;
return w;
}
}
回答by Fenton
You need to use HttpWebRequest
rather than WebClient
as you can't set the timeout on WebClient
without extending it (even though it uses the HttpWebRequest
). Using the HttpWebRequest
instead will allow you to set the timeout.
您需要使用HttpWebRequest
而不是WebClient
因为您不能在WebClient
不扩展它的情况下设置超时(即使它使用HttpWebRequest
)。使用HttpWebRequest
代替将允许您设置超时。
回答by dariom
As Sohnee says, using System.Net.HttpWebRequest
and set the Timeout
property instead of using System.Net.WebClient
.
正如 Sohnee 所说,使用System.Net.HttpWebRequest
和设置Timeout
属性而不是使用System.Net.WebClient
.
You can't however set an infinite timeout value (it's not supported and attempting to do so will throw an ArgumentOutOfRangeException
).
但是,您不能设置无限超时值(不支持并且尝试这样做会抛出ArgumentOutOfRangeException
)。
I'd recommend first performing a HEAD HTTPrequest and examining the Content-Length
header value returned to determine the number of bytes in the file you're downloading and then setting the timeout value accordingly for subsequent GET
request or simply specifying a very long timeout value that you would never expect to exceed.
我建议首先执行HEAD HTTP请求并检查Content-Length
返回的标头值以确定您正在下载的文件中的字节数,然后相应地为后续GET
请求设置超时值或简单地指定一个很长的超时值永远不要期望超过。
回答by GlennG
For completeness, here's kisp's solution ported to VB (can't add code to a comment)
为了完整起见,这里是移植到 VB 的 kisp 解决方案(不能在注释中添加代码)
Namespace Utils
''' <summary>
''' Subclass of WebClient to provide access to the timeout property
''' </summary>
Public Class WebClient
Inherits System.Net.WebClient
Private _TimeoutMS As Integer = 0
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal TimeoutMS As Integer)
MyBase.New()
_TimeoutMS = TimeoutMS
End Sub
''' <summary>
''' Set the web call timeout in Milliseconds
''' </summary>
''' <value></value>
Public WriteOnly Property setTimeout() As Integer
Set(ByVal value As Integer)
_TimeoutMS = value
End Set
End Property
Protected Overrides Function GetWebRequest(ByVal address As System.Uri) As System.Net.WebRequest
Dim w As System.Net.WebRequest = MyBase.GetWebRequest(address)
If _TimeoutMS <> 0 Then
w.Timeout = _TimeoutMS
End If
Return w
End Function
End Class
End Namespace
回答by Josh
'CORRECTED VERSION OF LAST FUNCTION IN VISUAL BASIC BY GLENNG
Protected Overrides Function GetWebRequest(ByVal address As System.Uri) As System.Net.WebRequest
Dim w As System.Net.WebRequest = MyBase.GetWebRequest(address)
If _TimeoutMS <> 0 Then
w.Timeout = _TimeoutMS
End If
Return w '<<< NOTICE: MyBase.GetWebRequest(address) DOES NOT WORK >>>
End Function
回答by themullet
Couldn't get the w.Timeout code to work when pulled out the network cable, it just wasn't timing out, moved to using HttpWebRequest and does the job now.
拔出网络电缆时无法使 w.Timeout 代码工作,它只是没有超时,转移到使用 HttpWebRequest 并立即完成工作。
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(downloadUrl);
request.Timeout = 10000;
request.ReadWriteTimeout = 10000;
var wresp = (HttpWebResponse)request.GetResponse();
using (Stream file = File.OpenWrite(downloadFile))
{
wresp.GetResponseStream().CopyTo(file);
}
回答by Davinci Jeremie
The first solution did not work for me but here is some code that did work for me.
第一个解决方案对我不起作用,但这里有一些代码对我有用。
private class WebClient : System.Net.WebClient
{
public int Timeout { get; set; }
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest lWebRequest = base.GetWebRequest(uri);
lWebRequest.Timeout = Timeout;
((HttpWebRequest)lWebRequest).ReadWriteTimeout = Timeout;
return lWebRequest;
}
}
private string GetRequest(string aURL)
{
using (var lWebClient = new WebClient())
{
lWebClient.Timeout = 600 * 60 * 1000;
return lWebClient.DownloadString(aURL);
}
}
回答by Konstantin S.
Usage:
用法:
using (var client = new TimeoutWebClient(TimeSpan.FromSeconds(10)))
{
return await client.DownloadStringTaskAsync(url).ConfigureAwait(false);
}
Class:
班级:
using System;
using System.Net;
namespace Utilities
{
public class TimeoutWebClient : WebClient
{
public TimeSpan Timeout { get; set; }
public TimeoutWebClient(TimeSpan timeout)
{
Timeout = timeout;
}
protected override WebRequest GetWebRequest(Uri uri)
{
var request = base.GetWebRequest(uri);
if (request == null)
{
return null;
}
var timeoutInMilliseconds = (int) Timeout.TotalMilliseconds;
request.Timeout = timeoutInMilliseconds;
if (request is HttpWebRequest httpWebRequest)
{
httpWebRequest.ReadWriteTimeout = timeoutInMilliseconds;
}
return request;
}
}
}
But I recommend a more modern solution:
但我推荐一个更现代的解决方案:
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public static async Task<string> ReadGetRequestDataAsync(Uri uri, TimeSpan? timeout = null, CancellationToken cancellationToken = default)
{
using var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
if (timeout != null)
{
source.CancelAfter(timeout.Value);
}
using var client = new HttpClient();
using var response = await client.GetAsync(uri, source.Token).ConfigureAwait(false);
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
It will throw an OperationCanceledException
after a timeout.
它会OperationCanceledException
在超时后抛出一个。
回答by Alex
For anyone who needs a WebClient with a timeout that works for async/task methods, the suggested solutions won't work. Here's what does work:
对于需要适用于异步/任务方法的超时 WebClient 的任何人,建议的解决方案将不起作用。这是有效的方法:
public class WebClientWithTimeout : WebClient
{
//10 secs default
public int Timeout { get; set; } = 10000;
//for sync requests
protected override WebRequest GetWebRequest(Uri uri)
{
var w = base.GetWebRequest(uri);
w.Timeout = Timeout; //10 seconds timeout
return w;
}
//the above will not work for async requests :(
//let's create a workaround by hiding the method
//and creating our own version of DownloadStringTaskAsync
public new async Task<string> DownloadStringTaskAsync(Uri address)
{
var t = base.DownloadStringTaskAsync(address);
if(await Task.WhenAny(t, Task.Delay(Timeout)) != t) //time out!
{
CancelAsync();
}
return await t;
}
}
I blogged about the full workaround here
我在这里写了关于完整解决方法的博客
回答by antoine
In some cases it is necessary to add user agent to headers:
在某些情况下,需要将用户代理添加到标头中:
WebClient myWebClient = new WebClient();
myWebClient.DownloadFile(myStringWebResource, fileName);
myWebClient.Headers["User-Agent"] = "Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
This was the solution to my case.
这是我的情况的解决方案。
Credit:
信用:
http://genjurosdojo.blogspot.com/2012/10/the-remote-server-returned-error-504.html
http://genjurosdojo.blogspot.com/2012/10/the-remote-server-returned-error-504.html