Coder Perfect

How to alter a.NET WebClient object’s timeout

Problem

I’m trying to download data from a client to my local system (programatically), however their webserver is extremely slow, causing my WebClient object to time out.

Here’s what I came up with:

WebClient webClient = new WebClient();

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

Is there a way to make this object have an indefinite timeout? Can somebody provide me an example of a different way to do this if this isn’t possible?

In a browser, the URL works perfectly; it simply takes roughly 3 minutes to load.

Asked by Ryall

Solution #1

You can customize the timeout by inheriting the original WebClient class and overriding the webrequest getter, as shown in the example below.

In my situation, MyWebClient was a private class:

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

Answered by kisp

Solution #2

Although the original approach did not work for me, here is some code that did.

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

Answered by Davinci Jeremie

Solution #3

Because you can’t set the timeout on WebClient without extending it, you’ll need to use HttpWebRequest instead (even though it uses the HttpWebRequest). Instead, you can use the HttpWebRequest to set the timeout.

Answered by Fenton

Solution #4

When I couldn’t get the w.Timeout code to function after removing the network cable, it simply wouldn’t time out, so I switched to HttpWebRequest, which now works.

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

Answered by themullet

Solution #5

The offered solutions will not work for anyone who requires a WebClient with a timeout that works with async/task methods. Here’s what actually works:

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 detailed the workaround in this blog post.

Answered by Alex from Jitbit

Post is based on https://stackoverflow.com/questions/1789627/how-to-change-the-timeout-on-a-net-webclient-object