2009-11-24 20 views
175

Sto provando a scaricare i dati di un client sul mio computer locale (programmaticamente) e il loro server web è molto lento che causa un timeout nel mio oggetto WebClient.Come modificare il timeout su un oggetto WebClient .NET

Ecco il mio codice:

WebClient webClient = new WebClient(); 

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

C'è un modo per impostare un timeout infinito su questo oggetto? O se no qualcuno può aiutarmi con un esempio su un modo alternativo per fare questo?

L'URL funziona correttamente in un browser: bastano circa 3 minuti per essere visualizzati.

risposta

310

È possibile estendere il timeout: ereditare la classe WebClient originale ed eseguire l'override del getter di richiesta Web per impostare il proprio timeout, come nell'esempio seguente. MyWebClient era una classe privata nel mio caso

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

qual è il timeout predefinito ?? – knocte

+16

Il timeout predefinito è 100 secondi. Anche se sembra funzionare per 30 secondi. –

+3

http: // stackoverflow.com/domande/601.861/set-timeout-per-webclient-DownloadFile – Evgeny

17

è necessario utilizzare HttpWebRequest piuttosto che WebClient come non è possibile impostare il timeout sul WebClient senza estenderla (anche se usa il HttpWebRequest). Usando il HttpWebRequest invece ti permetterà di impostare il timeout.

+0

Questo non è vero ... potete vedere qui sopra, che è comunque possibile utilizzare WebClient, anche se un'implementazione personalizzata che sostituisce il WebRequest per impostare il timeout. – DomenicDatti

+7

"System.Net.HttpWebRequest.HttpWebRequest() 'è obsoleto:' Questa API supporta l'infrastruttura .NET Framework e non è progettata per essere utilizzata direttamente dal codice" – usefulBee

+2

@usefulBee - perché non è necessario chiamare tale costruttore: ' "Non utilizzare il costruttore HttpWebRequest.Usare il metodo WebRequest.Create per inizializzare i nuovi oggetti HttpWebRequest." 'Da https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest(v=vs.110) aspx. Vedi anche http://stackoverflow.com/questions/400565/is-there-any-way-to-inherit-a-class-without-constructors-in-net – ToolmakerSteve

7

Come dice Sohnee, utilizzando System.Net.HttpWebRequest e impostare la proprietà Timeout invece di utilizzare System.Net.WebClient.

Non è tuttavia possibile impostare un valore di timeout infinito (non è supportato e il tentativo di farlo genererà un valore ArgumentOutOfRangeException).

mi consiglia prima di eseguire una richiesta HEAD HTTP ed esaminando il valore Content-Length intestazione restituito per determinare il numero di byte del file che si sta scaricando e quindi impostare il valore di timeout di conseguenza per la successiva richiesta GET o semplicemente specificando un tempo molto lungo valore di timeout che non ti aspetteresti mai di superare.

7

Per completezza, ecco la soluzione di KISP portata su VB (non può aggiungere il codice a un commento)

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
'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

Impossibile ottenere il w.Timeout codice per funzionare quando tirato fuori il cavo di rete, non era solo il timeout, spostato a utilizzare HttpWebRequest e fa il lavoro ora.

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

Questa risposta grandi opere, ma per chiunque interessati, se si utilizza 'var = wResp attendono request.GetResponseAsync();' invece di var wResp = (HttpWebResponse) request.GetResponse '();' si otterrà di nuovo un timeout massiccia – andrewjboyd

8

La prima soluzione non ha funzionato per me, ma qui è un codice che ha funzionato per 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); 
     } 
    } 
Problemi correlati