4

I build this method (c#) in order to receive the HTTP response status code from an URL. whene I run this method ones it's works fine, but when I run it in a loop, the third time its stuck. any clue??

 public static string isAlive(string url)
    {
        Console.WriteLine("start: Is Alive Test");
        WebRequest request = WebRequest.Create(url);
        try
        {
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            return Convert.ToString((int)response.StatusCode);
        }
        catch(WebException ex)
        {
            HttpWebResponse res  = (HttpWebResponse)ex.Response;
            return Convert.ToString((int)res.StatusCode);
        }
    }

the loop

        for (int i = 0; i < 5; i++)
        {
            string a = isAlive("https://www.yahoo.com/");
            Console.WriteLine(a);
        }
SIE-Coder
  • 105
  • 1
  • 7
  • Are you sure it's stuck and not just waiting for a response? There's good chance that the server is throttling the requests because it might detect suspicious activity (throwing so many requests to a server in such a short space of time can appear to be a DoS attack). Given you want to make numerous requests without blocking the UI thread you might want to consider going for `BeginX`/`EndX` calls instead. – James Feb 20 '14 at 09:48
  • Define 'stuck'. If your program is hanging after three attempts it could be that the yahoo server is rejecting your rapid succession of `https` requests. Another alternative is that your OS is preventing rapid connections to the same address (internal flood protection). edit - the answer is the other alternative, you have too many connections open at once. – Adam Kewley Feb 20 '14 at 09:49
  • You need to wrap .GetResponse() into `using` statement and make your isAlive method async for performance considerations. See my code sample below. – Konstantin Tarkus Feb 20 '14 at 09:59
  • @James, I never said that wrapping `GetResponse` into `using` makes it async. Where did you get that from? – Konstantin Tarkus Feb 20 '14 at 10:15

4 Answers4

10

You're not calling Dispose on the HttpWebResponse object, which means that the connection is still lying around. If you change your code to the following:

public static string isAlive(string url)
{
   Console.WriteLine("start: Is Alive Test");
   WebRequest request = WebRequest.Create(url);
   try
   {
       using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            return Convert.ToString((int)response.StatusCode);
        }

   }
   catch(WebException ex)
   {
       using(HttpWebResponse res  = (HttpWebResponse)ex.Response)
       {
          return Convert.ToString((int)res.StatusCode);
       }
   }
}

the using statement will implicitly call Dispose for you, which will close the connection.

The reason your code is halting after the second iteration is because .Net has a built in maximum number of connections it will open to a website, which is by default 2. This is controlled by System.Net.ServicePointManager.DefaultConnectionLimit which you can increase should you need to.

Ceilingfish
  • 5,397
  • 4
  • 44
  • 71
  • I think you have to do the same for `ex.Response`. – Steven Liekens Feb 20 '14 at 09:50
  • Although I agree they should wrap this with `using`, I doubt it's the cause of the problem. The `response` object would get disposed once it goes out of scope of the `isAlive` call eventually (not immediately though). Nor should this affect subsequent calls. – James Feb 20 '14 at 09:51
  • @James that's assuming that you leave the app enough time for the garbage collector to clean up after every iteration. – Steven Liekens Feb 20 '14 at 09:53
  • 1
    The framework uses connection pooling to handle HTTP requests, so not immediately closing the connection is a plausible cause of this problem. – Steven Liekens Feb 20 '14 at 09:55
  • @StevenLiekens actually I stand corrected, the default max connection is 2 as per the [docs](http://msdn.microsoft.com/en-us/library/1tkaca2y(v=vs.110).aspx) - so this more than likely *is* the problem so +1. – James Feb 20 '14 at 09:57
1
  • You need to wrap HttpWebResponse var into using statement because it's disposable
  • Before checking ex.Response.StatusCode make sure that ex.Status is a ProtocolError
  • And also consider making your method asynchronous for performance considerations
  • Since your method is returning a status code, there might be a better name for it than isAlive

Sample:

public static async Task<string> GetStatusCode(string url)
{
    var request = (HttpWebRequest)WebRequest.Create(url);

    try
    {
        using (var response = (HttpWebResponse)await request.GetResponseAsync())
        {
            return response.StatusCode.ToString();
        }
    }
    catch (WebException ex)
    {
        return ex.Status == WebExceptionStatus.ProtocolError ?
                ((HttpWebResponse)e.Response).StatusCode.ToString() : null;
    }
}
Konstantin Tarkus
  • 37,618
  • 14
  • 135
  • 121
0

It might have to do with you not closing the HttpWebResponse. Add a finally to that try catch which closes the response. Also close the WebException response within the catch.

smidy
  • 54
  • 2
0

Use "using" and it will work well.

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            return Convert.ToString((int)response.StatusCode);
        }
Jaroslav Kadlec
  • 2,505
  • 4
  • 32
  • 43