This post is the second part of my previous post where we discussed six tips to improve the performance of ASP.NET applications. In this post, we are going to discuss six more tips that could be another round a booster for your application performance. The link to the previous post is below.

6 Make your page asynchronous

IIS uses CLR thread pool to get a thread that processes a request that comes to the application. Say, if there are currently twenty threads available in the pool, it means only twenty requests can be served in parallel, and if request processing takes some time then it could turn into a disaster if hundred odd requests are bombarded in few milliseconds. In this case, some of the requests may take very long time and for some may return 404 status code. For any request, the significant part of the time is gone when the request goes out of current scope like going to the database and fetching or reading/writing file, calling the web services, etc. During that period, current thread keeps waiting till the response is returned. So if we make the page asynchronous and time-consuming calls are handled asynchronously, then we can increase the throughput considerably. To process a page asynchronously, add an async directive in the page as

Also now writing asynchronous code became so easy with the introduction of async and await keyword. We can write asynchronous methods and can use it with the help of RegisterAsyncTask method of the page.

7 Application Pool Suspension - This feature got introduced with Windows Server 2012 R2 and .NET 4.5.1. IIS provides a setting Idle Timeout for application pools which are by default set as 20 minutes. It means that if there is no request for 20 minutes, worker process (w3wp.exe) will stop to save the server resources. But it has a side effect, as the worker process currently stopped, the next request becomes a victim because while serving it, the worker process is required to restart and initialized. Worker process restart is an expensive and time taking process as it includes lots of tasks like process start, initialize configurations, initialize asp.net, load the binaries etc in memory.

This feature allows us to suspend the process instead of stopping it. After the suspension, it releases most of CPU and memory which becomes available for other sites hosted on the same server. But it is maintained in a state if a request comes, it will become active quickly and start serving the request. It is similar to suspension in windows apps where we have concepts of active and suspended apps. It helps in two folds, first it allows us to serve more optimally by adding more application and even the request which comes after a timeout, also served quickly without much difference with active ones. We can configure in any app pool as

Select application pool -> advanced settings

8 Remove methods from Global.asax – Global.asax provides us some application level methods where some gets fired once on the first request while others fired in each request. Most of the time, we have empty methods in this files, which forces asp.net to execute those methods even if there is no code inside. On each request, ASP.NET looks if there is any method available in Global.asax and if yes, then it loads and executes it accordingly. So as a first thing, we should remove empty methods and even if we can remove some methods from there by putting the code at some other place in page lifecycle, then it will be also helpful.

9 Don’t use SqlDataSource – Avoid using SqlDataSource as the data source for data controls like GridView. In case of GridView, if paging is enabled, on page number click, it fetches all the records from the database and then applies the paging by own. Same is true for sorting as well. Instead use model binding introduced in ASP.NET 4.5, where we can use IQueryable queries and use select method etc to return the list of items. IQueryable behind the scene optimize and create the SQL queries smartly that fetches only the required data from the database like only ten records instead of all the records or sort the data at the database level. That makes the paging and sorting very efficient. Similarly, we can use QueryableDataSource or ObjectDataSource as well.

10 Use HTTP Keep-Alive - It is another hidden gem which resides in response header and helps in improving the performance of our web applications significantly. This response header keeps the client and server connection open for a specific duration and it is utilized by multiple requests. In case the connection is open, the time for creating a new connection gets saved which enables the server to send the response very quick. By default, it is enabled it and the connection is opened for 120 seconds. If it is disabled, it behaves as HTTP 1.0 where only one request per connection is allowed. We can configure it on IIS as

Go to IIS -> Select the desired website-> Open HTTP Response Headers -> Click on Set Common Headers from action tab at right

It is by default enabled (refer the encircled area). Verify it to check whether your application is leveraging this feature or not.

Note – For IIS 7.5 and above, this header tag is removed from the response header and by default, it is enabled as discussed but there is another header tag in opposite case. If it is disabled then in response header there is a new header is available as Connection: close. It means the connection is closed after the request.

11 Remove ETag - Let’s have a look at one HTTP response header

Here we can see that there one element as ETag (Refer Red encircled). Let’s try to understand the way it is used. Whether any response is served by the client cache or not, depends on two items: One is Cache-Control and Expires attribute and another ETag. ETag is a hash code that is created on the web server for each content and in case of the content of the file changes, hash changes which invalidates the cache. In Web Farm scenario, hash created on a different server will be different even if the content is same because hash also depends on the server as well. So the request won’t be served from the cache even if the content is same if the request goes to another web server. So it is better if we remove this tag itself to get the better use of client cache if the application is hosted in a web farm.

12 This tip is a set of few very important configuration changes, which can make a significant impact on the performance of your application.

a. We discussed earlier that IIS uses CLR thread pool to serve the request. Let’s take an example, if our application receives even 100 requests simultaneously and this number of threads are not available in the thread pool, then some of them have to wait. CLR starts creating new threads to assign each request. Creating new threads is a pretty heavy process, and in earlier versions of .net, the rate of creating threads was two seconds per thread while in the latest version, it is around 0.5 second. Considering 0.5 sec per thread, creating eighty threads will take forty seconds so we can understand that the response time would vary at least 1-40 second. You can imagine the situation if a number of request goes 500 or 1000.

There is one setting in machine.config which is by default as

Which we can change as

maxWorkerThreads = "200" />

As we have set the minWorkerThread count as 100, it will reduce the time spent on creating each thread and IIS will be ready to take the requests quickly. Please note the above settings are on per core CPU basis.

b. There is another important setting available in applicationHost. Config (can be set at application pool level) as maxConcurrentRequestsPerCPU (available in IIS 7+) which is in latest versions is 5000, can be tweaked based on requirement. As the name suggests, it sets the limits the number of concurrent requests can be processed by the application.

c. maxConnection is another very important configuration. It limits the number of connection can be created to some other system. The default value was 2 in earlier versions of.NET. It comes into the picture when web server makes a call to another machine in the network like database/wcf services etc. It means at a point in time only two connections can be made, even if you have high-end servers with good connectivity. It can be changed at machine level or application level as

Here we have changed it to one hundred. Based on requirement, we can increase or decrease but it is advised keep it moderate number else it could be an overkill. Apart from that, we can provide more specific details like IP address or domain information to limit it to specific server(s) in network.

Conclusion – In this series, we discussed following twelve tips, most of them we can easily apply without any code change that can enhance the performance of your web application drastically. These are

1 Kernel mode Cache

2 Pipeline mode

3 Remove unused modules

4 runAllManagedModulesForAllRequests

5 Don’t write in wwwroot

6 Remove unused view engines and language

7 Make your page asynchronous

8 Application Pool Suspension

9 Remove methods from Global.asax

10 Don’t use SqlDataSource

11 Use HTTP Keep-Alive

12 Remove ETag

I tried to discuss the tips which are normally ignored but they have huge performance enhancement potential and can be applied quickly as well. Some common tricks like Bundling and Minification, IIS compression, ViewState, client caching are very important but well known they did not include in the series.