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”>
- 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
- 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.
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.