Today's topic involves WebExceptions and their proper handling.  Along the way, we'll talk a little about HttpWebResponse, ServicePoint and connection limits.

Whenever you write an application that communicates on the web, you inevitably run into connection issues (site moved, incorrect access credentials, insufficient privileges to view the site, etc).  .NET applications inform you of these issues by throwing a WebException when you attempt to establish your connection (by calling HttpWebRequest.GetResponse()).

The handling of a WebException requires a bit of care.  This brings us to the topic of resonses and connection limits.

The .NET Compact Framework has a default connection limit, per ServicePoint (more on these later), of two (2).  What this means is that you can only have two open connections on a given ServicePoint at the same time. 

You may be asking what constitutes a ServicePoint.  ServicePoints are made up of the scheme (ex: http), the host (ex: www.microsoft.com) and the port (ex:80).  Paths, query strings, etc are not taken into consideration as part of the ServicePoint.  This means that if you connect to both "folderA/page1.htm" and "folderB/page2.htm" on the same server, using the same port, you will have consumed the maximum number of connections on your service point (http://www.microsoft.com:80, in our example).

While you can increase the connection limit using the following,

// set connection limit to 5
ServicePointManger.DefaultConnectionLimit = 5;

I only recommend doing this if the users of your application must have more than two connections to any given server open at the same time.

Which brings us back to handling WebExceptions...

When your application catches a WebException, the first thing you should do is extract the response:

try
{
    // http connection code
}
catch(WebException we)
{
    // check the response
    HttpWebResponse response = we.Response as HttpWebResponse;

    // the rest will be filled in below
}

If the response is not null (Nothing in VisualBasic.NET), you can extract more information regarding the reason for the exception (from the HttpWebResponse.StatusCode property).  Once you have the data, be sure to close the response object.  This will release the connection and allow you to make another connection to the same server,

try
{
    // http connection code
}
catch(WebException we)
{
    // check the response
    HttpWebResponse response = we.Response as HttpWebResponse;

    if(null != response)
    {
        // get the reason for the exception
        HttpStatusCode status = response.StatusCode;
        String description = response.StatusDescription;
   
        // close the response
        response.Close();
    }

    // do any further exception processing here
}

Handling web exceptions in this way allows your application to take recovery steps (ex: re-prompt for credentials and retry the connection) and/or to display connection failure information to your customers.

Earlier, I mentioned that you can change the connection limit.  If you are going to change the default value, please note that any active service points will not abide by the new limit.  To ensure that all service points use the desired limit, you should modify the connection prior to making any connections (ex: at application startup).

Take care,
-- DK

[Edit: Fixed formatting && add missing null check]

Disclaimers:
This posting is provided "AS IS" with no warranties, and confers no rights.
Some of the information contained within this post may be in relation to beta software.  Any and all details are subject to change.