12

I'm having a problem finding out how to close the connection made by WebClient. I create a new WebClient object and then call DownloadFile method a lot of times, however, it always creates a new connection for each call and those connections stay open (Established state), I can see in TCPView all the established connections.

What bugs me even more if when I dispose the Webclient, they stay established...? How to force the connection to be closed after the download is done?

I already tried to derive WebClient and set keep alive manually to false, my app config allow enough connections as well.

<connectionManagement>
  <add address="*" maxconnection="1000"/>
</connectionManagement>
Lasty01
  • 123
  • 1
  • 1
  • 6
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders May 11 '13 at 21:27
  • How many connections at maximum? Looks like keep-alive. – usr May 11 '13 at 21:31
  • @usr even if it's keep-alive, shouldn't the connection be closed if the webclient is disposed? – Julián Urbano May 11 '13 at 21:33
  • 1
    .NET pools connections across object instances. This is normal. Again, how many? – usr May 11 '13 at 21:34

1 Answers1

22

Short answer: you shouldn't need to close the connections manually. They are managed for you behind the scenes.

HTTP/1.1 connections are not closed as soon as the request completes in order that multiple requests to the same server are handled in a more timely and efficient manner (such as a web browser requesting multiple files from a single site). You shouldn't have to worry about this or close them down manually, as they'll timeout after a while. Is it causing an error?

If it is an issue, you could try inheriting from WebClient and overriding the GetWebRequest method to manually set KeepAlive, e.g.:

public class NoKeepAlivesWebClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri address)
    {
        var request = base.GetWebRequest(address);
        if (request is HttpWebRequest)
        {
            ((HttpWebRequest)request).KeepAlive = false;
        }

        return request;
    }
}

I'd also always suggest using the using pattern for WebClient:

using (var client = new NoKeepAlivesWebClient())
{
    // Some code
}

Finally, here's some RFC information about persistent connections in HTTP/1.1:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html

and a friendlier Wikipedia entry:

http://en.wikipedia.org/wiki/HTTP_persistent_connection

Edit:

Apologies. I see from your edited question that you've already tried something like the above, without success.

I was unable to reproduce your issue, however. I wrote a small program using the NoKeepAlivesWebClient and it successfully closed connections after they were used, according to TCPView.

static void Main(string[] args)
{
    // Random test URLs
    var urls = new List<string> {
        "http://msdn.microsoft.com/en-us/library/tt0f69eh.aspx",
        "http://msdn.microsoft.com/en-us/library/system.net.webclient.allowreadstreambuffering.aspx",
        "http://msdn.microsoft.com/en-us/library/system.net.webclient.allowwritestreambuffering.aspx",
        "http://msdn.microsoft.com/en-us/library/system.net.webclient.baseaddress.aspx",
        "http://msdn.microsoft.com/en-us/library/system.net.webclient.cachepolicy.aspx",
        "http://msdn.microsoft.com/en-us/library/system.net.webclient.credentials.aspx",
        "https://www.youtube.com/",
        "https://www.youtube.com/feed/UClTpDNIOtgfRkyT-AFGNWVw",
        "https://www.youtube.com/feed/UCj_UmpoD8Ph_EcyN_xEXrUQ",
        "https://www.youtube.com/channel/UCn-K7GIs62ENvdQe6ZZk9-w" };

    using (var client = new NoKeepAlivesWebClient())
    {
        // Save each URL to a Temp file
        foreach (var url in urls)
        {
            client.DownloadFile(new Uri(url), System.IO.Path.GetTempFileName());
            Console.WriteLine("Downloaded: " + url);
        }
    }
}

There's another SO question here about the same issue:

C# get rid of Connection header in WebClient

Community
  • 1
  • 1
Dave R.
  • 7,206
  • 3
  • 30
  • 52
  • Thanks for all the infos, however I already tried exactly the same thing, no luck, I also tried to set Timeout and ReadWriteTimeout to 10 seconds but no effect as well. I need to close them because I'm using a lot of DownloadFile and after a while, I have like 200 etablished connections in tcpviews, that makes no sense – Lasty01 May 11 '13 at 22:12
  • Sorry, @Lasty01 I didn't see your edit before posting my answer. I've edited it to add another option for you. – Dave R. May 11 '13 at 22:14
  • thanks again, but nothing seems to work... I tried this for now : protected override WebRequest GetWebRequest(Uri address) { WebRequest request = base.GetWebRequest(address); if (request is HttpWebRequest) { var webRequest = request as HttpWebRequest; webRequest.CookieContainer = CookieContainer; webRequest.KeepAlive = false; webRequest.Timeout = 10000; webRequest.ReadWriteTimeout = 10000; } return request; } – Lasty01 May 12 '13 at 03:43
  • @Lasty01 - I cannot reproduce the issue, I'm afraid. Are you sure you're downloading over HTTP or HTTPS? – Dave R. May 12 '13 at 15:03
  • 1
    Well my bad, I found the error, I was calling OpenRead to get the filesize somewhere else, and I was disposing the webclient, but that was not enough, I had to store the stream returned by OpenRead in a var and dispose it explicitly, sorry for the confusion here, problem resolved, thanks all. – Lasty01 May 12 '13 at 18:37
  • Overriding that method doesn't (no longer?) works... `'NoKeepAlivesWebClient.GetWebRequest(System.Uri)': cannot change access modifiers when overriding 'protected' inherited member`. – mellis481 Jul 03 '14 at 18:12
  • @im1dermike - I've updated the example, changing `public` to `protected` to get it working again. – Dave R. Jul 04 '14 at 10:04