47

Why does the following code Timeout the second (and subsequent) time it is run?

The code hangs at:

using (Stream objStream = request.GetResponse().GetResponseStream())

and then causes a WebException saying that the request has timed out.

I have tried this with a WebRequest and HttpWebRequest

Edit: It seems the code is falling over in request.GetResponse()

Edit: This post suggests it may be a GC issue --> http://www.vbforums.com/showthread.php?t=610043 - as per this post the issue is mitigated if Fiddler is open in the background.

The server is there and available for requests.

    private string GetQLMResponse(string URL)
    {
        HttpWebRequest request = WebRequest.Create(URL) as HttpWebRequest;
        request.Credentials = new NetworkCredential(Settings.Default.LicenseUser, Settings.Default.LicensePassword);
        request.KeepAlive = false;
        request.Timeout = 5000;
        request.Proxy = null;

        // Read stream
        string responseString = String.Empty;
        try
        {
            using (var response = request.GetResponse())
            {
                using (Stream objStream = response.GetResponseStream())
                {
                    using (StreamReader objReader = new StreamReader(objStream))
                    {
                        responseString = objReader.ReadToEnd();
                        objReader.Close();
                    }
                    objStream.Flush();
                    objStream.Close();
                }
                response.Close();
            }
        }
        catch (WebException ex)
        {
            throw new LicenseServerUnavailableException();
        }
        finally
        {
            request.Abort();
            request = null;
            GC.Collect();
        }
        return responseString;
    }

Thrown WebException is:

{"The operation has timed out"} [System.Net.WebException]: {"The operation has timed out"} Data: {System.Collections.ListDictionaryInternal} HelpLink: null InnerException: null Message: "The operation has timed out" Source: "System" StackTrace: " at System.Net.HttpWebRequest.GetResponse()\r\n at IQX.Licensing.License.GetQLMResponse(String URL) in C:\Users\jd\SVN\jd\Products\Development\JAD.Licensing\JAD.Licensing\License.cs:line 373" TargetSite: {System.Net.WebResponse GetResponse()}


Update: OK So the following code now works. The servicePoint was setting the timeout to be near 4 minutes. Changing ServicePoint.ConnectionLeaseTimeout on the request object means that the request is now destroyed after 5000ms. Thanks to all for your help and also to these 2 pages:

  1. http://blogs.msdn.com/b/adarshk/archive/2005/01/02/345411.aspx
  2. http://msdn.microsoft.com/en-us/library/6hszazfz(v=VS.80).aspx

    private string GetQLMResponse(string URL)
    {
        HttpWebRequest request = WebRequest.Create(URL) as HttpWebRequest;
        request.Credentials = new NetworkCredential(Settings.Default.LicenseUser, Settings.Default.LicensePassword);
        request.KeepAlive = false;
        request.Timeout = 5000;
        request.Proxy = null;
    
        request.ServicePoint.ConnectionLeaseTimeout = 5000;
        request.ServicePoint.MaxIdleTime = 5000;
    
        // Read stream
        string responseString = String.Empty;
        try
        {
            using (WebResponse response = request.GetResponse())
            {
                using (Stream objStream = response.GetResponseStream())
                {
                    using (StreamReader objReader = new StreamReader(objStream))
                    {
                        responseString = objReader.ReadToEnd();
                        objReader.Close();
                    }
                    objStream.Flush();
                    objStream.Close();
                }
                response.Close();
            }
        }
        catch (WebException ex)
        {
            throw new LicenseServerUnavailableException();
        }
        finally
        {
            request.Abort();
        }
        return responseString;
    }
    
Darbio
  • 11,286
  • 12
  • 60
  • 100

10 Answers10

31

On the heels of the previous answers, I wanted to add a couple more things. By default HttpWebRequest allows only 2 connections to the same host (this is HTTP 1.1 "niceness"),

Yes, it can be overriden, no I won't tell you how in this question, you have to ask another one :) I think you ought to look at this post.

I think that you are still not quite disposing of all your resources connected with the HttpWebRequest, so the connection pooling comes into play and that's the problem. I wouldn't try to fight the 2 connections per server rule, unless you really have to.

As one of the posters above noted, Fiddler is doing you a bit of a disservice in this case.

I'd add a nice finally {} clause after your catch and make sure that as the above post notes, all streams are flushed, closed and references to the request object are set to null.

Please let us know if this helps.

Community
  • 1
  • 1
dawebber
  • 3,503
  • 1
  • 16
  • 16
  • 1
    Thanks. I have tried forcing it to use HTTP 1.0. I have tried setting the request to null. And then doing a `GC.Collect()` - to no avail. – Darbio Apr 29 '11 at 03:18
  • @JD, GC.Collect() shouldn't be necessary here. I think that for some reason, your connections don't terminate properly. Have you tried 2Sam B's suggestion to just use a simple Windows forms app and repro the problem? Is this service internet facing or internal? Could there be some restriction on how often you can connect to it from the same IP? – dawebber Apr 29 '11 at 03:39
  • 1
    @JD, also try doing `netstat -n | find /i ""`, where is the IP of the service. How many times is it listed and what state are the connections in? – dawebber Apr 29 '11 at 03:41
  • 2 connections, response of netstat -an: TCP 192.168.15.51:57126 175.x.x.x:80 ESTABLISHED TCP 192.168.15.51:57128 175.x.x.x:80 TIME_WAIT – Darbio Apr 29 '11 at 04:03
  • Service is internet facing with basic authentication – Darbio Apr 29 '11 at 04:04
  • @JD, this tells me that the 2 previous connections you established don't go away when you try to make the third one. I know I said I won't share that info in this question, but add this line before you init HttpWebRequest: `ServicePointManager.DefaultConnectionLimit = 3`. Some more good info is [available here](http://blogs.msdn.com/b/adarshk/archive/2005/01/02/345411.aspx, but you'll need to know more about the server to take advantage of some of the advice given in this post. If you now are able to get 3 connections before the nest one gets queued up --> – dawebber Apr 29 '11 at 04:18
  • @dawebber: setting `ServicePointManager.DefaultConnectionLimit = 3` (also tried 10) still does not allow the response to be read. I will read that blog now. – Darbio Apr 29 '11 at 04:22
  • --> then you are on the right track. I'd look at other properties in the ServicePointmanagerClass and try to tweak them. Connections only get elibible for GC when their lifetime is expired, hence the advice not to call GC.Collect yourself. I would say that this advice is not something I'd do in production, but it might be beneficial for troubleshooting your issue. – dawebber Apr 29 '11 at 04:23
  • 1
    @JD, try turning off TCPKeepAlive on the ServicePointManager, by setting the appropriate timeouts, etc. I still think something is weird here, and the server is not RFC2616-compliant or there is some sort of a strange reverse proxy in front of it or there is connection throttling in place on the server side. – dawebber Apr 29 '11 at 04:26
  • 2
    @dawebber: Thanks, I have now got it working using the `request.ServicePoint` class and settings properties on that. This was also of help --> http://msdn.microsoft.com/en-us/library/6hszazfz(v=VS.80).aspx – Darbio Apr 29 '11 at 04:33
  • 1
    @dawebber: The server is IIS 7.5 and 'should' be compliant. It is now working by altering the timeouts to 5 seconds. Thanks for your help :) – Darbio Apr 29 '11 at 04:37
  • @JD, btw, Service Point exposed is created by the factory in ServicePointManager. Glad you got it working! It's always very frustrating when you are stuck with an issue like that. – dawebber Apr 29 '11 at 04:40
24

The WebResponse obtained by request.GetReponse() MUST be disposed properly. Try this (removing request.Abort() and GC.Collect() calls):

using (var wresponse = request.GetResponse())
{
   using (Stream objStream = wresponse.GetResponseStream())
   {
        // ...
   }
}

Edit: Since it still does not work, I suggest you to test this with an empty windows application. This way, you could isolate app.config problems or maximum concurrent calls per host* (are you using other webrequest object somewhere else in your application to this host; which webresponse are not disposed properly?).

Hope this solve your problem, I am out of ideas!

  • See Jon Skeet's answer here.
Community
  • 1
  • 1
Sam B
  • 2,441
  • 2
  • 18
  • 20
  • Thanks, but this is still causing the same issue to occur. I have updated the source code above to reflect your suggestions. – Darbio Apr 29 '11 at 02:27
  • AFAIK WebResponse does not implement IDisposable. – Darbio Apr 29 '11 at 02:36
  • @JD: Yes it does. WebResponse class signature: `public abstract class WebResponse : MarshalByRefObject, ISerializable, IDisposable` (http://msdn.microsoft.com/en-us/library/system.net.webresponse(v=VS.90).aspx). Howver, WebRequest DOES NOT implement IDisposable. – Sam B Apr 29 '11 at 02:40
  • @JD: Can you post the Exception message caught in your try-catch (with the updated code)? – Sam B Apr 29 '11 at 02:46
  • @SamB: I stand corrected - I could not see the Dispose method in Intelisense... Just positing exception above. – Darbio Apr 29 '11 at 02:53
  • @JD: You are not seeing a Dispose method because the IDisposable interface is Explicitely implemented. – Sam B Apr 29 '11 at 02:56
  • Failing to properly Close() the response is the only cause for this issue that I've seen over the last several years. – EricLaw Apr 29 '11 at 03:15
  • @EricLaw: Can you see how I am not closing the response? I am suspecting that the request is the only thing which could be causing an issue as it is the only object not disposed of? – Darbio Apr 29 '11 at 03:20
  • @JD: The only things which is disposable (and which needs to be disposed) is the Response. Try my latest edit; and disable Fiddler. Your Timeout is sets to 5 seconds, can the server take more than 5 seconds to respond? – Sam B Apr 29 '11 at 03:22
  • No the server is responding within 100ms at all times. Fiddler is closed. Response is being disposed. – Darbio Apr 29 '11 at 03:27
  • This is in a standalone windows application now. Still same problems – Darbio Apr 29 '11 at 03:27
  • Thanks - simply disposing the response object fixed this issue for me – Darren Gosbell Dec 02 '14 at 01:30
10

As you have stated, running fiddler in the background would mitigate the issue. This is because fiddler force closes any responses. Extending on the above post from Sam B I would ensure that the response is closed like so:

using (var wresponse = request.GetResponse())
{
   using (Stream objStream = wresponse.GetResponseStream())
   {
        // ...
   } 
   wresponse.close();
}

Also it may be worth setting the proxy to null like so:

 request.Proxy = Null;

As the .NET framework will go out searching for a proxy unless you explicitly do this. When fiddler is running this effect would be mitigated as fiddlers proxy would be found directly.

Sean Hunter
  • 1,041
  • 8
  • 19
  • That's odd. Only other thing that I can suggest is this fix from Phil Haak: http://haacked.com/archive/2004/05/15/http-web-request-expect-100-continue.aspx – Sean Hunter Apr 29 '11 at 02:38
  • Your answer seemed like the most improbable to me, but it's what happened - I forgot to close the response in a different function (I wasn't even looking there). – Arman Bimatov Jan 07 '15 at 16:33
5

ran into the same problem with timeouts on subsequent requests to the server despite disposing/flushing/closing everything properly. try flushing your connection group, worked for me:

myRequest.ServicePoint.CloseConnectionGroup(myRequest.ConnectionGroupName);

also, ensure you're not inadvertently creating other HttpWebRequest/Request objects elsewhere in your application that aren't being properly terminated/disposed, as this will increase the numbers of connections in the Service Point.

rdltrr
  • 76
  • 1
  • 3
1

I had the same issue, and I resolved it ensuring I call the Abort() method on each of the request object created.

0

By any chance were you using a test app with the default name of WindowsFormsAppN? I had the same problem that I spent a week debugging because it worked in my production code but not in a simple test solution I was building. In the end, I determined this behavior was unique to using the default solution name instead of a properly named solution.

Edit: I discovered my issue was related to using BitDefender as my AV software. The WindowsFormsAppN programs were all blocked.

oldSchool
  • 31
  • 3
0

I read the post tagged as answer above and it didn't really work for me above. I ended up rewriting the code using the using tags and added a CloseConnectionGroup segment someone else recommended here. Ultimately this is what the code looks like:

System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(imageUrl);
                webRequest.AllowWriteStreamBuffering = true;
                webRequest.Timeout = 30000;
                webRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
                webRequest.ServicePoint.MaxIdleTime = 5000;

                using (System.Net.WebResponse webResponse = webRequest.GetResponse())
                {

                    using (System.IO.Stream stream = webResponse.GetResponseStream())
                    {
                        image = System.Drawing.Image.FromStream(stream);
                    }
                }

                webRequest.ServicePoint.CloseConnectionGroup(webRequest.ConnectionGroupName);
                webRequest = null; 
            }
Be05x5
  • 117
  • 12
0

Done with me when add this

myRequest.ServicePoint.CloseConnectionGroup(myRequest.ConnectionGroupName);
Tungtata
  • 11
  • 2
0

for anyone looking for second time timeouts in vb.net: make sure you have been using:

  1. response.close()

  2. response.dispose()

after every time you have used your webresponse.

Positive Navid
  • 2,481
  • 2
  • 27
  • 41
-3

I've set http time out to 10 minutes and it worked for me.

Setting to timeout=infinite was taking more time and my program was going in hung mode.

Nikolay Kostov
  • 16,433
  • 23
  • 85
  • 123