Understanding System.Net Connection Management and ServicepointManager


If you are already using System.Net.HttpWebRequest class and familiar with request/response programming model for WebRequest in .net frameworks, you might be interested in getting inside the connection management handling of HttpWebRequest and to understand how you could apply it effectively in your application.

In this article, you will understand the basics of connection management story of HttpWebRequest and how ServicepointManager and HttpWebRequest properties could be used to tune the connection management.

For the simplicity I did narrow down this post to simple scenarios to focus on connection management mechanism

a)      Request is Anonymous (no authentication)

b)      “GET” request,

c)      No Proxy server is involved,

d)      No caching involved – .net frameworks 2.0 added support for caching on HttpWebRequest, but for simplicity here we assume caching is disabled,

e)      Request timeouts are also not described here,

In future posting I promise to provide more details about specific  scenarios like POST request, authentication, proxy server and also for other protocols like FtpWebRequest and SmtpClient, which were added in .net frameworks 2.0.

Creating first WebRequest

Before we jump into details of connection management, take a fresh first look on the things happening behind the scene, when you are making first HttpWebRequest from your application. Following are two simple line of code would create a request and send it on the wire.

WebRequest request = WebRequest.Create(“http://blogs.msdn.com/adarshk”);

WebResponse response = request.GetResponse();

So as soon as your application invoke the GetResponse() method there are number things happened. Following is the sequence of operations took place.

a)      System.Net see it is a first request, it creates a connection group for it,

b)      Since this is new connection group, it also creates a servicepoint on this group (for the sack of simplicity, assume that there is no authentication involved and servicepoint is on per host basis),

c)      It creates a new connection and open a new socket connection to remote host,

d)      A NetworkStream is created on top of the connection and complete http request,

e)      It wait for http response header data from remote host and once all headers are received, response.Headers structure is filled,

Next thing you might be doing in your application is either looking into response headers or reading response for the request as below

Stream readStream = response.GetResponseStream();

At this point the stream composed for the current connection and handed over to the user code, so user app could read the actual content of the request. After complete the reading on the stream, user app suppose to close the response stream.

readStream.Close();

So when readStream is closed, we indicate the System.Net that that app code is done with this request and connection is now freely available for upcoming other requests. If this request object  had specifically set the “KeepAlive = false”, then connection would be closed at this point, by default KeepAlive = true. Let’s assume we did make the request with KeepAlive enabled.

Following diagram is sort of representing, the the relationship between ServicePoint, ConnectionGroup, Coonections.


> > Next HttpWebRequest

Now we are done with the first http request in application and let’s make second request. There are many possible scenarios to handle on second request. Let’s assume your second request is going on the same server:port as in previous request.

Second Request after finishing the previous request

This is simplest scenario, because you already closed the response Stream, connection is now freely available for second request. Second request would be send on the same connection as previous request, no new connection is created. Same sequence of operations would be followed as for the normal first request.

 

Second Request before finishing the first request – Pipelining

If we are making second request without finishing the first one then connection limit come to the picture. Default value of connection limit is 2, it is as per following the guidelines of http RFC2616. If we didn’t reach at connection limit, then on same service point new connection would get created and request would be send on new connection, but if we had reached the maximum connection limit then request would be queued on the one of the connection. How request would be queued depends on the pipelining.

Pipelining turned on

If pipelining is turned on (pipelining is available only against http 1.1 servers), request could be send to the server even if previous request was not completed as shown on following figure.

Server will respond on the requests in the same sequence as it received.

Pipelining turned off

If pipelining is turned off, then server can not accept the new request, unless it completed the previous requests, so new requests would be kept in a pending queue and when the current responseStream for current request is closed by the user then this new request is send on the wire as displayed on following diagram.

Following flowchart is a simplified representation of sequence of operations on connection management.


Queuing multiple requests

I believe now you have a better picture about what happened on first request and what happened with the connection on subsequent next request. If application continues to make requests, all pending requests would be queued on the ServicePoint and processed sequentially. If pipeline is turned on, then request is send on the connection and put in the queue of the connection. If pipelining is turned off then request would remain on the queue of the servicepoint and would be sending on the connection, as soon as free connection is available. Following diagram explains this in detail.

Recycling the connection

After getting inside of all this basic connection management, next natural question arise is how long we will keep the connection alive, when should we cleaned the connection and create new connections.

Whenever server chooses to close the connection, then off course client side has to close the connection. New connection would be created for future requests to same server. When server is not closing the connection from its side, then client need to optimize the connection management and only keep necessary connections alive via closing unwanted connections.

There are some properties on Servicepoint and ServicepointManager classes, which controls the lifetime of the connections.

Idle connections

Each ServicePoint instance maintains its connection only until it has been idle longer than the time specified in the MaxIdleTime property. Once a ServicePoint exceeds the MaxIdleTime, connection can be recycled (closed). The default value of MaxIdleTime is set by the MaxServicePointIdleTime property on ServicePointManager.

By default, when KeepAlive is true for a request, the MaxIdleTime property sets the timeout for closing ServicePoint connections due to inactivity. If the ServicePoint has active connections, MaxIdleTime has no effect and the connections remain open indefinitely.

Connection lease timeout

This property is added in .net frameworks 2.0. There are some specific scenarios where it is more optimal to close the current active connection to the server and establish a new connection, especially in case where server side have load balancing mechanism (e.g. Web Garden scenario, where load is dynamically distributed across multiple servers for load balncing). This Servicepoint.ConnectionLeaseTimeout allows user to close the active connection and new connection would be created for subsequent requests.

One important thing to note about connection cleanup, there is no separate thread is monitoring the connection status, cleanup of connection is performed when user application is making the requests, at that ServicePointManager verify the state of the connection and perform cleanup operation if required.

 

This posting is provided “AS IS” with no warranties, and confers no rights

Comments (26)

  1. I have been trying to use the httpWebRequest to retrieve an aspx file and pass it to excel. I can pass the HTML fine, but the code behind is never ran. This means I get tags like <asp:label> in my excel – and obviously excel doesnt recognise them.

    Is there are way of screen scrapping my own aspx file as it would appear in a normal browser?

    Here is my code:

    Dim req As WebRequest = HttpWebRequest.Create(url)

    Dim results As String

    Try

    ‘Get the data as an HttpWebResponse object

    Dim resp As WebResponse

    resp = req.GetResponse()

    ‘Convert the data into a string (assumes that you are requesting text)

    Dim sr As New StreamReader(resp.GetResponseStream())

    results = sr.ReadToEnd()

    sr.Close()

    Catch wex As WebException

    ‘Something went awry in the HTTP request!

    End Try

    Label1.Text = results

    my email is jagdip.ajimal@mbagroup.net

  2. adarsh khare says:

    Hi Jagdip,

    HttpWebResponse will provide you the exact content (stream of bytes) send by the server, in your case if server is sending the right html, your code look perfect and “results” should contain the actual response html send bey server.

    It may be incorrect application directory configuration issue on server side. To confirm you could try to make request in browser to same url and see what response you are getting.

    Thanks

    adarsh

  3. Arun says:

    Hello Adarsh,

    I have been trying to get internal web page of Linksys Access point from .net application using HttpWebRequest, I tried with NetworkCredentials, but it is failing with 401 Unauthorized exception.

    Here is my code.

    NetworkCredential myCred = new NetworkCredential();

    myCred.Password = "sas";

    HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://192.168.1.220/setup.htm&quot;);

    myCred.Domain = "Linksys WAP11";

    HttpWebResponse resp = (HttpWebResponse)req.GetResponse();

    Please help.

  4. adarsh says:

    Are you sure the code you are giving is correct, I am seeing atleast two issues

    1) Username property is not set on myCred, also make sure domain name is correct it looks incorrect for me,

    2) you need to add credential to actual WebRequest like below

    req.Credential = myCred;

  5. I love posts like this that explain how to tune System.Net.&amp;nbsp; System.Net.ServicePoint has long been…

  6. jgough says:

    This is a great article, I’m learning more about HttpWebRequest by the day. Yesterday I finally learned how to attach an X509Certificate to my request + process a custom forms-based authentication redirect on the remote end.

    What I want to be able to do is create a generally unobtrusive way to proxy any outbound request through a certain type of "filter". There is a potential that any incoming request on the remote end will be redirected to a custom HTML login page. The code in my link processes this login page properly to retrieve the session cookies from the remote end.

    But, can you recommend a way for achieving a non-inheritance based method of generalizing this scheme?

    I guess a Proxy might be the best choice. The outbound request will first go through the proxy. The proxy will determine whether or not the request has been redirected to the login page. If so, it processes it, then returns the ultimate result to the caller.

    Thanks!

    Josh

  7. smalldust says:

    Excellent article.

    I have noticed that msdn says:

    Your application cannot mix synchronous and asynchronous methods for a particular request. If you call the BeginGetRequestStream method, you must use the BeginGetResponse method to retrieve the response.

    In my mind, getting a request stream has nothing to do with a remote server, so I just want simply call the synchronous version of it. But the mix of GetRequestStream and BeginGetResponse seems to be failed: the BeginGetResponse will also execute synchronously, just like a GetResponse.

    Do you know the reason? Thanks.

  8. smalldust says:

    Excellent article.

    I have noticed that msdn says:

    Your application cannot mix synchronous and asynchronous methods for a particular request. If you call the BeginGetRequestStream method, you must use the BeginGetResponse method to retrieve the response.

    In my mind, getting a request stream has nothing to do with a remote server, so I just want simply call the synchronous version of it. But the mix of GetRequestStream and BeginGetResponse seems to be failed: the BeginGetResponse will also execute synchronously, just like a GetResponse.

    Do you know the reason? Thanks.

  9. smalldust says:

    Excellent article.

    I have noticed that msdn says:

    Your application cannot mix synchronous and asynchronous methods for a particular request. If you call the BeginGetRequestStream method, you must use the BeginGetResponse method to retrieve the response.

    In my mind, getting a request stream has nothing to do with a remote server, so I just want simply call the synchronous version of it. But the mix of GetRequestStream and BeginGetResponse seems to be failed: the BeginGetResponse will also execute synchronously, just like a GetResponse.

    Do you know the reason? Thanks.

  10. Steve Messer says:

    Is it true that when using pipelining with the .net framework that Webrequests using the verb POST won’t be pipelined?

    I have read that somewhere and I can’t seem to make pipelining work using POST.

    Thanks

  11. Ajay says:

    Hi Adarsh,

    I am suppose to undertake some project work in which , I am suppose to access the html tags of a website, then extract the value of that, lies between the code body.E.g. <Html> …. </html>

    What can be the optimal code to do this ?

    email: ajay@comcastsolutions.com

  12. Abhijeet Dhanapune says:

    I am working on a webscraping tool to retrieve data from a webpage as fast as possible. This program instantiates multiple instances of a scraper class (my class) which has a timer that fires every one second. Following code is executed on timer_elapsed

    m_Wrequest = System.Net.HttpWebRequest.Create(m_URL);

    m_Wrequest.Timeout = 1000;

    ((HttpWebRequest)m_Wrequest).KeepAlive = false;

    string HTMLContents ="";

    StreamReader sr = null;

    try

    {

           objResponse = m_Wrequest.GetResponse();

           sr = new StreamReader(objResponse.GetResponseStream());

           HTMLContents = sr.ReadToEnd();

    }

    catch (WebException ex)

    {

          Log.GetInstance().Error(ex.Message,ex.Status,);

    }

    finally

    {

          if(objResponse!=null)

             objResponse.Close();

          if(sr != null)

             sr.Close();

    }

    I am getting ‘The operation timed out’ errors sporadically. I am also measuring the time taken for m_Wrequest.GetResponse() to return back and even in case of the errors this time is less than timeout threshold set for my HttpWebRequest. This is making it difficult to find the cause of the problem. I am definitely closing my connections as soon as I get data. I was wondering if .NET takes some time to return these connections back to connection pool and may be which is why they are not available once in a while.

  13. panefsky says:

    Very compact and informative.

    The strem.close() thing saved the day!

    thanx

  14. Kanika says:

    Hi Abhijeet Dhanapune

    I am facing the same problem are you able to resolve it.

    In my case it is systematic that after every 2 request 3 gives the error.

    Please help

  15. Mateen says:

    Hi

    I m doing a project that is internet protected

    in project if som wb site like wwww.google.com is not

    accsebale in my system internet explorer

    so. how we can trace  this side

    give me some good ideas

  16. rukeba says:

    Many thanks!

    Very useful post!

  17. pradeep says:

    Nice post Adarsh,

    I`m facinf a problem,

    i have a threaded console application which is making request for a site, means each thread is making request to the same site but with different unique ID to get different data.

    but the this is these application is not requesting as fast as i am expecting it. means either it is getting queued or some sort of this.

    even if i increase the number of instance of the same console application then also it is not using extra bandwidth (i have 100Mbps) but app is using 2-3% even if i increase the instances of console application.

    could you please provide some feedback for the same.

    i want to use more bandwidth and make more number of requests per minute.

    thanks

    Pradeep

  18. sibitg says:

    Some times I am getting the following exception -"System.InvalidOperationException: The maximum number of service points was exceeded.". I am not setting "ServicePointManager.MaxServicePoints" anywhere in my code? What are the scenarios where this exceptions can occur?

  19. sibitg says:

    Some times I am getting the following exception in my WCF client -"System.InvalidOperationException: The maximum number of service points was exceeded.". I am not setting "ServicePointManager.MaxServicePoints" anywhere in my code? What are the scenarios where this exceptions can occur?

  20. Senthil says:

    Very good post! I am having an issue similar to what Abhijeet is having. The functionality of my code block is very similar to what Abhijeet posted. Create a request object, then read the response. I have multiple threads calling this function and every time a new webrequest object is created. Everything works fine for hours, but after a while all the threads hit "Operation timed out" error. Every single request after that gets the "Operation timed out" error. Is it because of the long queue at the servicepoint? All the timeouts happen exactly in 100 seconds which is the .NET default client timeout. Anyone has any clue on how to handle this? Should I set the connectiongroupname property for each thread? What is the impact (performance) of setting connectiongroupname for each request? Hope someone can answer my questions. Thanks!

  21. Aneesh says:

    am developing an application which makes the login and do some actions in the next page.am using httpwebrequest class and am successfully logged into the first page (after login page )..but when am tryng for the next page request with some values (post method )..its not working…its again coming to the login page..please help me to find out a solution

  22. Oh My God! You use Comic Sans to display code! Credibility lost! Ban Comic Sans!

  23. Bill says:

    Could you repost the diagrams? those images are missing and I really need to take a look to understand the article.

    Thanks.