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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 20:50:46  来源:igfitidea点击:

How to change the timeout on a .NET WebClient object

c#.netfiledownloadwebclient

提问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 WebClientobject.

我正在尝试将客户端的数据下载到我的本地机器(以编程方式),并且他们的网络服务器非常非常慢,这导致我的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 HttpWebRequestrather than WebClientas you can't set the timeout on WebClientwithout extending it (even though it uses the HttpWebRequest). Using the HttpWebRequestinstead will allow you to set the timeout.

您需要使用HttpWebRequest而不是WebClient因为您不能在WebClient不扩展它的情况下设置超时(即使它使用HttpWebRequest)。使用HttpWebRequest代替将允许您设置超时。

回答by dariom

As Sohnee says, using System.Net.HttpWebRequestand set the Timeoutproperty 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-Lengthheader value returned to determine the number of bytes in the file you're downloading and then setting the timeout value accordingly for subsequent GETrequest 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 OperationCanceledExceptionafter 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