4

I'm working on a C# project that uses a public XML feed for calculations. I originally used XmlDocument.Load, but migrated to WebClient.DownloadString so I could include headers in my request. The feed I'm accessing usually responds quickly, but every now and again it fails to respond within the timeout period of the WebClient object, and I get an exception. Here's my code:

XmlDocument xmlDoc = new XmlDocument();

Webclient client = new WebClient();
client.Headers["User-Agent"] = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1";
client.Headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";

string data = client.DownloadString(/*URL*/);

xmlDoc.LoadXml(data);

I've read that you cannot change the timeout property of WebClient, and people who have this problem should use HttpWebRequest instead. Unfortunately, I don't know how to go about implementing this in a way that still allows me to use my headers AND send that result to xmlDoc. Due to the nature of this application, I don't care how long it takes to receive the data; I can handle alerting the user.

What is the best way to go about doing this?

Community
  • 1
  • 1
Sonic42
  • 689
  • 1
  • 14
  • 21

3 Answers3

15

You could use a WebClient derived class for this, which just adds the timeout you want for each fetch:

public class TimeoutWebClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri address)
    {
        HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
        request.Timeout = 60000; //1 minute timeout
        return request;
    }
}

If you use TimeoutWebClient instead of WebClient now, you get the timeout behavior that you want. If the custom headers you need are the same for each request, you could add those here as well and your calling code remains very clean.

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
  • Just to confirm, I can stick your code just any ol' place and then use TimeoutWebClient exactly the same as WebClient? – Sonic42 Oct 23 '11 at 18:36
  • Always worth adding that webclient is IDisposable, as such so will TimeoutWebClient; get your `using` on :) – Chris McKee Apr 03 '14 at 15:42
1
XmlDocument xmlDoc = new XmlDocument();

HttpWebRequest request = new (HttpWebRequest)WebRequest.Create(/*URL*/);
request.Headers = new WebHeaderCollection();
// fill in request.Headers...

// The response is presented as a stream. Wrap it in a StreamReader that
// xmlDoc.LoadXml can accept.
xmlDoc.LoadXml(new StreamReader(request.GetResponse().GetResponseStream());
Anders Abel
  • 67,989
  • 17
  • 150
  • 217
0

You could just catch the exception, then reissue the request. You might want to put some other logic in here to abort after a certain number of failed attempts.

bool continue;
do{
    continue = false;     
    try {
        string data = client.DownloadString(/*URL*/);
    } 
    catch (WebException e) {
        continue = true;
    }
} 
while(continue);
Erik Funkenbusch
  • 92,674
  • 28
  • 195
  • 291
  • @MystereMan What if server is slow and responds in -say- 10 mins everytime? – L.B Oct 23 '11 at 18:35
  • Doesn't that create an infinite loop if the request is successful? – Sonic42 Oct 23 '11 at 18:37
  • @L.B - He said it usually responds fast, and only occasionally times out. It may be that the server aborts and never completes the request, so a long timeout will just wait until it times out no matter how long. – Erik Funkenbusch Oct 23 '11 at 18:38
  • @MystereMan But your code doesn't show how to set a short timeout, So that any new trial can be done quickly. – L.B Oct 23 '11 at 19:14
  • @L.B - trial? what are you talking about? Why would you want to set a short timeout? That's ridiculous. – Erik Funkenbusch Oct 23 '11 at 21:52
  • What ridiculous is your comment, If I knew that the server responds in 5 sec most of the time, why should I wait 100s(default) to timeout? A timeout -say- 20s would be enough. – L.B Oct 23 '11 at 22:56