Performance Tuning in ASP.Net Web Applications

The web application performance issue arises when the number of users increases in the application or it can also occur after a few days in production or during load testing in UAT. At this point, it's a tedious task to fix the performance issues since efforts are more toward making code changes and henceforth everyone blames developers for this issue.

The major tasks can categorize as being performance tuning issues are Collect Data, Analyze Results, Fine-tune the code and again test it for performance measure in an iterative fashion.

The following are the points which one needs to check before collecting data as a .Net developer.

Set debug=false in web.config

When you create the ASP.Net web application, by default this attribute is set to "true" in the web.config file that is very useful when developing. However, when you are deploying your application, always set it to "false". Setting it to "true" requires the pdb information to be inserted into the file and that results in a comparatively larger file and hence processing will be slow. So always set debug="false" before deployment.

Turn off Tracing unless until required

Tracing enables us to track the applications trace and the sequences that the developer needs to monitor the trace. When trace is enabled it tries to add extra information to the page. Always set this to "false" unless you require monitoring the trace logging in the production web.config.

<trace enabled="false" requestLimit=”10” pageoutput=”false” traceMode=”SortByTime” localOnly=”true”>  

Choose Session State management carefully

One extremely powerful feature of ASP.NET is its ability to store session state for users for any web applications. Since ASP.NET manages session state by default, we pay the cost in memory even if you don't use it. In other words, whether you store your data in in-process or on a state server or in a SQL Database, session state requires memory and it's also time consuming when you store or retrieve data from it.  You may not require session state when your pages are static or when you do not need to store information captured in the page. In such cases where you need not use session state, disable it on your web form using the directive:
<@%Page EnableSessionState="false"%>  
In case you use the session state only to retrieve data from it and not to update it, make the session state read-only using the following directive.
<@%Page EnableSessionState ="ReadOnly"%>  
If the application needing session mode state is out of process then consider carefully whether there is a need of the state server or SQL Server session mode. SQL Server session mode provides lower performance than session state server mode.

Don't store Session Sate to store objects of any type (including objects you create) since they are stored by serializing and then de-serializing them and that results in a big performance penalty.

Use the client-side session state management technique to transfer data from one page to other page like query string and clientsidestorage if possible.

Deploy with Release Build

Be sure you use Release Build mode and not Debug Build when you deploy your site to production. If you think this doesn't matter, think again. By running in debug mode, you are creating PDBs and cranking up the timeout. Deploy Release mode and you will see the speed improvements.

Disable View State of a Page if possible

View state is a technique in ASP.NET for storing some state data in a hidden input field inside the generated page. When the page is posted back to the server, the server can parse, validate and apply this view state data back to the page's tree of controls.

View state is a very powerful capability since it allows state to be persisted with the client and it requires no cookies or server memory to save this state. Many ASP.NET server controls use view state to persist settings made during interactions with elements on the page; for example, saving the current page that is being displayed when paging through data. 

The default behaviour of the View State property is enabled, but if you don't need it, you can turn it off at the control or page level. Within a control, simply set the EnableViewState property to false, or set it globally within the page using this setting.

<%@ Page EnableViewState="false" %>

Avoid Response.Redirect

To do client-side redirection in ASP.NET, users can call Response.Redirect and pass the URL. When Response.Redirect is called, the server sends a command back to the browser telling it to request the page redirected to it. An extra roundtrip happens that affects the performance. We can send information from the source page using a query string. There is a limitation on the length of a query string, it cannot be used to pass large amounts of data over the wire.

To do server-side redirection, users can use Server.Transfer. Since the execution is transferred on the server, Server.Transfer does not require the client to request another page. In Server.Transfer, by using HttpContext we can access the source page's items collection in the target page. The drawback of using this method is that the browser does not know that a different page was returned to it. It displays the first page's URL in the browser's address bar. This can confuse the user and cause problems if the user tries to bookmark the page. Transfer is not recommended since the operations typically flow through several pages.

Use StringBuilder to concatenate strings

All the manipulations you do to the string are stored in memory as separate references and it must be avoided as much as possible. In other words, when a string is modified, the runtime will create a new string and return it, leaving the original to be garbage collected. Most of the time this is a fast and simple way to do it, but when a string is being modified repeatedly it begins to be a burden on performance, all of those allocations eventually get expensive. Use StringBuilder whenever a string concatenation is needed so that it only stores the value in the original string and no additional reference is created.

Don't throwing exceptions

Exceptions cause slowdowns you will never see in web applications, as well as Windows applications. You can use as many try/catch blocks as you want. Using exceptions gratuitously is where you lose performance.

Use Finally Method to kill resources

The finally method gets executed independent of the outcome of the block. Always use a finally block to kill resources like closing database connections, closing files and other resources such that they are executed independent of whether the code in the try worked or went to the catch.

Use Client-side Scripts for validations

Client-side validation can help reduce round trips required to process a user's request. In ASP.NET you can also use client-side controls to validate user input. However, do a check at the server side too to avoid the infamous JavaScript disabled scenarios.

Avoid unnecessary round trips to the server

Round trips significantly affect performance. They are subject to network latency and to downstream server latency. Many data-driven Web sites heavily access the database for every user request. Whereas connection pooling helps, the increased network traffic and processing load on the database server can adversely affect performance. Keep round trips to an absolute minimum. Implement Ajax UI whenever possible. The idea is to avoid full page refresh and only update the portion of the page that needs to be changed.

Use Page.ISPostBack

Be sure you don't execute code needlessly. Use the Page.ISPostBack property to ensure that you only perform page initialization logic when a page is first time loaded and not in response to client postbacks.

Use Foreach loop instead of For loop for String Iteration

A foreach statement is far more readable and in the future it will become as fast as a for loop for special cases like strings. Unless string manipulation is a real performance hog for you, the slightly messier code may not be worth it. Use a LINQ query expression when needed.

Choose correct collections object

Choose the right collection object that does better over another. For example, an ArrayList is better than an array because an ArrayList has everything that is good about an array plus automatic sizing, Add, Insert, Remove, Sort, Binary Search. All these great helper methods are added when implementing the IList interface and the downside of an ArrayList is the need to cast objects upon retrieval. Carefully choosing a collection over another gives better performance.

Use Paging: The Grid Choice

Most web applications need the data to be shown in tabular format. For that we need a Grid view, DataGrid, JQgrid, Telerik grid, Kendo Grid UI and so on. When doing a selection we should use a thin grid that gives better performance. ASP.NET grid view uses server-side code and makes the page heavy, whereas JQGRID is faster since it does everything at the client side. Use paging to display data on a user demand basis instead of pulling a huge amount of data and showing it in a grid. Use a Repeater control instead of a DataGrid or DataList because it is efficient, customizable and programmable and faster in performance than that of a GridView, DataGrid and DataList.

Do Ajax calls instead of ASP.NET code behind code

Call a web service from JavaScript or jQuery instead of server-side. Use asynchronous calls to call a web method from a web service.

Store your content by using caching

ASP.NET allows you to cache entire pages, fragments of pages or controls. You can cache also variable data by specifying the parameters that the data depends on. By using caching you help the ASP.NET engine to return data for repeated request for the same page much faster. The proper use and fine tuning of the caching approach of caching will result in better performance and scalability of your site.

Use low cost authentication

Authentication can also have an impact on the performance of your application. For example, Passport authentication is slower than form-based authentication and that in turn is slower than Windows authentication.

Minimize the number of web server controls

The use of web server controls increases the response time of your application because they need time to be processed on the server side before they are rendered on the client side. One way to minimize the number of web server controls is to take into consideration the use of HTML elements where they are suited.

Avoid using unmanaged code

Calls to unmanaged code is a costly marshalling operation. Try to reduce the number of calls between the managed and unmanaged code. Consider doing more work in each call rather than making frequent calls to do small tasks. Use a using block.

Avoid Recursive Functions / Nested Loops

These are general things to adopt in any programming language that consumes much memory. Always avoid nested loops and recursive functions, to improve performance.

 - Make JavaScript and CSS External

Using external files generally produces faster pages because the JavaScript and CSS files are cached by the browser. Inline JavaScript and CSS increases the HTML document size but reduces the number of HTTP requests. With cached external files, the size of the HTML is kept small without increasing the number of HTTP requests, thus improving the performance.

 - Use multiple threads when calling multiple operations

The problem arises when single-threaded code gets stuck on a long-running process. So when we call multiple services in a single method we should call two methods in two different threads. Use of multiple threads makes the application more responsive.

Do a load test in the end of development cycle

Visual Studio provides options for doing load tests where we can test the application when the development is about to be complete. We can load as many users and set the duration and test it. By doing so we can easily learn which page has performance issues or the application itself is performing badly. This should be a part of the development process and reduces the cost of repair with less effort instead of waiting for someone to identify performance issues in the application.

 - Script rendering order and cleaning up Html code

If possible, you can move the script tags <script> to the very bottom of the page. The reason this is important is that during the rendering, when the browser comes across a <script> tag, it stops to process the script and then proceeds. If you put the script tags at the bottom of the page then the page/HTML will render faster and the scripts can execute after the DOM elements have loaded.

 - Remove the unused ViewEnginee from ASP.NET MVC Pipeline

By default the ASP.Net runtime provides two types of view engines in ASP.Net MVC applications. The unused view engines should be removed from the runtime. For example, if you use a Razor page then add the following code in your global.asax.cs. By default, ASP.Net MVC renders with an aspx engine and a Razor engine. This only uses the RazorViewEngine.

ViewEngines.Engines.Clear();  

ViewEngines.Engines.Add(new RazorViewEngine());  

 - Do not put C# code in your MVC view

Your ASP.NET MVC views are compiled at run time and not at compile time. Therefore if you include too much C# code in them, your code will not be compiled and placed in DLL files. Not only will that damage the testability of your software, it will also make your site slower because every view will take longer to be displayed (because they must be compiled). Another down side of adding code to the views is that they cannot be run asynchronously and so if you decide to build your site based on Task-based Asynchronous Pattern (TAP), you won't be able to take advantage of asynchronous methods and actions in the views.