.NET WebClient ऑब्जेक्ट पर टाइमआउट कैसे बदलें


230

मैं अपने स्थानीय मशीन (प्रोग्रामिक रूप से) के लिए एक ग्राहक का डेटा डाउनलोड करने का प्रयास कर रहा हूं और उनका वेबसर्वर बहुत, बहुत धीमा है जो मेरे WebClientऑब्जेक्ट में एक टाइमआउट का कारण बन रहा है ।

यहाँ मेरा कोड है:

WebClient webClient = new WebClient();

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

क्या इस वस्तु पर अनंत समय निर्धारित करने का कोई तरीका है? या यदि कोई ऐसा करने के लिए वैकल्पिक तरीके से उदाहरण के साथ मेरी मदद नहीं कर सकता है?

ब्राउज़र में URL ठीक काम करता है - इसे दिखाने में सिर्फ 3 मिनट लगते हैं।

जवाबों:


378

आप टाइमआउट का विस्तार कर सकते हैं: मूल WebClient वर्ग को इनहेरिट करें और अपने टाइमआउट को सेट करने के लिए वेबरेक्वेस्ट गेट्टर को ओवरराइड करें, जैसे निम्न उदाहरण में।

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 सेकंड के लिए चलता है।
कार्टर मेडलिन

2
एक टाइमपैन TimeSpan के साथ Timeout सेट करने के लिए थोड़ा आसान है। FromSeconds (20) .Milliseconds ... यद्यपि कोई समाधान नहीं है!
वेबवार्ता

18
@webwires एक का उपयोग करना चाहिए .TotalMillisecondsऔर नहीं .Milliseconds!
अलेक्जेंडर गल्किन

79
वर्ग का नाम होना चाहिए: PatientWebClient;)
जन विल्म बी

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इसके बजाय उपयोग करने की आवश्यकता है WebClientक्योंकि आप WebClientइसे विस्तारित किए बिना टाइमआउट सेट नहीं कर सकते हैं (भले ही यह उपयोग करता है HttpWebRequest)। HttpWebRequestइसके बजाय का उपयोग करने से आप टाइमआउट सेट कर पाएंगे।


यह सच नहीं है ... आप ऊपर देख सकते हैं कि आप अभी भी WebClient का उपयोग कर सकते हैं, समय-समय पर सेट करने के लिए WebRequest को ओवरराइड करने वाले कस्टम कार्यान्वयन के बावजूद।
DomenicDatti

7
"System.Net.HttpWebRequest.HttpWebRequest () 'अप्रचलित है:' यह API .NET फ्रेमवर्क इन्फ्रास्ट्रक्चर का समर्थन करता है और इसका आपके कोड से सीधे उपयोग करने का इरादा नहीं है"
उपयोगी जानकारी

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। यह मिलीसेकंड में है।
मार्सेल

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

पूर्णता के लिए, यहाँ 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

7

जैसा कि सोहनी कहते हैं, उपयोग 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 की जरूरत है जो async / कार्य विधियों के लिए काम करता है , सुझाए गए समाधान काम नहीं करेंगे। यहाँ क्या काम करता है:

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एक टाइमआउट के बाद फेंक देगा ।


काम नहीं किया, async विधि अभी भी अनिश्चित काल तक काम करती है
एलेक्स

शायद समस्या अलग है और आपको कन्फिगरएविट (गलत) का उपयोग करने की आवश्यकता है?
कोन्स्टेंटिन एस।

-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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.