.NET WebClient 개체에서 시간 초과를 변경하는 방법


230

클라이언트의 데이터를 로컬 컴퓨터 (프로그래밍 방식)로 다운로드하려고하는데 웹 서버가 매우 느려서 WebClient개체 가 시간 초과됩니다 .

내 코드는 다음과 같습니다.

WebClient webClient = new WebClient();

webClient.Encoding = Encoding.UTF8;
webClient.DownloadFile(downloadUrl, downloadFile);

이 객체에 무한 시간 초과를 설정하는 방법이 있습니까? 또는 다른 방법으로 다른 방법으로 나를 도울 수 없다면?

URL은 브라우저에서 제대로 작동합니다. 표시하는 데 약 3 분이 걸립니다.

답변:


378

다음 예제와 같이 시간 초과를 연장 할 수 있습니다. 원래 WebClient 클래스를 상속하고 webrequest getter를 재정 의하여 고유 한 시간 초과를 설정하십시오.

MyWebClient는 필자의 경우 개인 클래스였습니다.

private class MyWebClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri uri)
    {
        WebRequest w = base.GetWebRequest(uri);
        w.Timeout = 20 * 60 * 1000;
        return w;
    }
}

5
기본 시간 제한은 무엇입니까 ??
knocte

23
기본 시간 초과는 100 초입니다. 30 초 동안 실행되는 것 같습니다.
카터 메 드린

3
Timespan TimeSpan.FromSeconds (20) .Milliseconds ...를 사용하여 시간 초과를 설정하는 것이 조금 더 쉽습니다.
webwires

18
@webwires 하나는 사용 .TotalMilliseconds하지 말아야합니다 .Milliseconds!
Alexander Galkin

80
클래스 이름은 PatientWebClient;)
Jan Willem B

27

첫 번째 해결책은 나를 위해 작동하지 않았지만 여기에 나를 위해 일한 코드가 있습니다.

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

21

시간 초과를 확장하지 않고 설정할 수 없으므로 HttpWebRequest대신 사용해야합니다 (을 사용 하더라도 ). 은 Using 당신이 제한 시간을 설정 할 수 있습니다 대신.WebClientWebClientHttpWebRequestHttpWebRequest


이것은 사실이 아닙니다 ... WebRequest를 재정 의하여 시간 초과를 설정하는 사용자 정의 구현이지만 여전히 WebClient를 사용할 수 있음을 알 수 있습니다.
DomenicDatti

7
"System.Net.HttpWebRequest.HttpWebRequest () '는 더 이상 사용되지 않습니다.'이 API는 .NET Framework 인프라를 지원하며 사용자 코드에서 직접 사용할 수 없습니다"
usefulBee

3
@usefulBee - 당신이 생성자를 호출하지 않아야 때문에 : "Do not use the HttpWebRequest constructor. Use the WebRequest.Create method to initialize new HttpWebRequest objects."에서 msdn.microsoft.com/en-us/library/... . stackoverflow.com/questions/400565/…
ToolmakerSteve

명확히하기 위해 :이 특정 생성자를 피해야하지만 (더 이상 최신 .NET 버전의 일부는 아닙니다)의 Timeout속성 을 사용하는 것이 좋습니다 HttpWebRequest. 밀리 초입니다.
Marcel

10

네트워크 케이블을 뽑을 때 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);
}

1
이 답변은 훌륭하게 작동하지만 관심있는 사람 var wresp = await request.GetResponseAsync();은 var 대신 사용 wresp = (HttpWebResponse)request.GetResponse();하면 다시 큰 시간 초과가 발생합니다
andrewjboyd

andrewjboyd : 왜 GetResponseAsync ()가 작동하지 않는지 아십니까?
osexpert

9

완성도를 높이기 위해 여기에 kib의 솔루션이 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

7

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

5

비동기 / 태스크 메소드 에서 작동 하는 시간 초과가있는 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;
    }
}

나는 완전한 해결 방법에 대해 블로그에 여기


4

용법:

using (var client = new TimeoutWebClient(TimeSpan.FromSeconds(10)))
{
    return await client.DownloadStringTaskAsync(url).ConfigureAwait(false);
}

수업:

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

그러나 더 현대적인 솔루션을 권장합니다.

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

그것은 발생합니다 OperationCanceledException타임 아웃 후.


작업은하지 않았지만, 비동기 방식은 여전히 ​​무한정 작동합니다.
Alex

아마도 문제가 다르고 ConfigureAwait (false)를 사용해야합니까?
Konstantin S.

-1

경우에 따라 헤더에 사용자 에이전트를 추가해야합니다.

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)";

이것이 내 경우의 해결책이었습니다.

신용:

http://genjurosdojo.blogspot.com/2012/10/the-remote-server-returned-error-504.html

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.