Как изменить таймаут на объекте .NET WebClient
Я пытаюсь загрузить клиентские данные на свой локальный компьютер (программно), и их веб-сервер очень и очень медленный, что вызывает тайм-аут в моем WebClient
объекте.
Вот мой код:
WebClient webClient = new WebClient();
webClient.Encoding = Encoding.UTF8;
webClient.DownloadFile(downloadUrl, downloadFile);
Есть ли способ установить бесконечный тайм-аут на этом объекте? Или, если нет, кто-нибудь может мне помочь с примером для альтернативного способа сделать это?
URL-адрес отлично работает в браузере - для отображения требуется всего около 3 минут.
Ответы
Ответ 1
Вы можете продлить тайм-аут: наследовать исходный класс WebClient и переопределить метод получения веб-запросов, чтобы установить собственный тайм-аут, как в следующем примере.
MyWebClient был закрытым классом в моем случае:
private class MyWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest w = base.GetWebRequest(uri);
w.Timeout = 20 * 60 * 1000;
return w;
}
}
Ответ 2
Первое решение не сработало для меня, но вот какой-то код, который работал у меня.
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);
}
}
Ответ 3
Вам нужно использовать HttpWebRequest
, а не WebClient
, поскольку вы не можете установить таймаут на WebClient
, не расширяя его (хотя он использует HttpWebRequest
). Использование HttpWebRequest
вместо этого позволит вам установить тайм-аут.
Ответ 4
Не удалось заставить код 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);
}
Ответ 5
Для полноты, здесь решение kisp портировано на VB (не может добавить код в комментарий)
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
Ответ 6
Как говорит Sohnee, используя System.Net.HttpWebRequest
и устанавливая свойство Timeout
вместо System.Net.WebClient
.
Однако вы не можете установить бесконечное значение таймаута (оно не поддерживается, и попытка сделать это приведет к выбросу ArgumentOutOfRangeException
).
Я бы порекомендовал сначала выполнить HEAD HTTP запрос и изучить значение заголовка Content-Length
, возвращаемое для определения количества байтов в файле вы загружаете, а затем устанавливаете значение тайм-аута соответственно для последующего запроса GET
или просто указываете очень длинное значение таймаута, которое вы никогда не ожидаете превышать.
Ответ 7
'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
Ответ 8
Использование:
using (var client = new TimeoutWebClient(TimeSpan.FromSeconds(10)))
{
return await client.DownloadStringTaskAsync(url);
}
Класс:
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;
}
}
}
Ответ 9
Для тех, кому нужен 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 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;
}
}
Я в блоге о полном обходе здесь