Friday, August 09, 2013

C# WebClient .DownloadStringAsync Blocking Main Thread

Photo by Max Ronnersjö
While needing to invoke a url in the background from a C# 5.0 program, I was overjoyed to stumble across "WebClient .DownloadStringAsync(url)". I thought I'd found a bird's nest on the ground. 
Here was a single call to solve my problem. 
Great job Microsoft framework group!

Well, not so fast.

My unit tests for bad and malformed URLs were actually blocking.
The problem is that WebClient.DownloadStringAsync() blocks until the connection is made.  If your application happens to call a bad url, the main thread will block until it gets an error code back.  This can be up to 3 seconds for normal malformed urls.  In  one case, our internet proxy had problems with the malformed url and consistently hung for 10 seconds while it was sorting out the problem and eventually returned a timeout error.

If you ever suspect the url you are calling is ever going to have issues (and we know all sites are up all the time!  Right.), don't use DownloadStringAsync, use DownloadString() wrapped in a Thread or Task.  This way if the connection has problems, it's another thread's problem, and your main thread can move forward.

...
new Thread(() => DownloadUrlSynchronously(url)).Start();
...

public void DownloadUrlSynchronously(string url)
{
            using (WebClient client = new WebClient())
            {
                try
                {
                    var x = client.DownloadString(new Uri(url));
                    _logFileWrapper.LogInfo("Url called successful - " + _url);
                }
                catch (Exception e) { ...}
                ...
}

No comments: