ASP.NET is much more powerful than classic ASP, however it is important to understand how to use that power to build highly efficient, reliable and robust applications. In this article, I tried to highlight the key tips you can use to maximize the performance of your ASP.NET pages. The list can be much longer, I am only emphasizing the most important ones.
Research and investigate how .NET can really benefit you. .NET offers a variety of solutions on each level of application design and development. It is imperative that you understand your situation and pros and cons of each approach supported by this rich development environment. Visual Studio is a comprehensive development package and offers many options to implement the same logic. It is really important that you examine each option and find the best optimal solution suited for the task at hand. Use layering to logically partition your application logic into presentation, business, and data access layers. It will not only help you create maintainable code, but also permits you to monitor and optimize the performance of each layer separately. A clear logical separation also offers more choices for scaling your application. Try to reduce the amount of code in your code-behind files to improve maintenance and scalability.
If not handled properly, String Concatenation can really decrease the performance of your application. You can concatenate strings in two ways.
StringBuilder
Class. Below is an example of both approaches. If you are considering doing any type of String Concatenation, please do yourself a favor and test both routines separately. You may be surprised at the results.
1
'
Concatenation using String Class
2
Response.Write(
"
<b>String Class</b>
"
)
3
Dim str As String
=
""
4
Dim startTime As DateTime
=
DateTime.Now
5
Response.Write((
"
<br>Start time:
"
+
startTime.ToString()))
6
Dim i As Integer
7
For i
=
0
To
99999
8
str
+=
i.ToString()
9
Next i
10
Dim EndTime As DateTime
=
DateTime.Now
11
Response.Write((
"
<br>End time:
"
+
EndTime.ToString()))
12
Response.Write((
"
<br># of time Concatenated:
"
+
i.ToString))
13
Results: Took 4 minutes and 23 Seconds to to complete 100,000 Concatenations.
String
Class
1
'
Concatenation using StringBuilder
2
Response.Write(
"
<b>StringBuilder Class</b>
"
)
3
Dim strbuilder As New StringBuilder()
4
Dim startTime As DateTime
=
DateTime.Now
5
Response.Write((
"
<br>Start time:
"
+
startTime.ToString()))
6
Dim i As Integer
7
For i
=
0
To
99999
8
strbuilder.Append(i.ToString())
9
Next i
10
Dim EndTime As DateTime
=
DateTime.Now
11
Response.Write((
"
<br>Stop time:
"
+
EndTime.ToString()))
12
Response.Write((
"
<br># of time Concatenated:
"
+
i.ToString))
13
Results: Took less than a Second to complete 100,000 Concatenations.
StringBuilder
Class
This is one of the many situations in which ASP.NET provides extremely high performance benefits over classic ASP.
You can avoid needless round trips to the Web Server using the following tips:
<atlas:updatepanel>
control. Page.ISPostBack
property to ensure that you only perform page initialization logic when a page is loaded the first time and not in response to client postbacks. If Not IsPostBack Then
LoadJScripts()
End If
ViewState
is used primarily by Server controls to retain state only on pages that post data back to themselves. The information is passed to the client and read back in a hidden variable. ViewState
is an unnecessary overhead for pages that do not need it. As the ViewState
grows larger, it affects the performance of garbage collection. You can optimize the way your application uses ViewState
by following these tips:
ViewState
is turned on in ASP.NET by default. You might not need ViewState
because your page is output-only or because you explicitly reload data for each request. You do not need ViewState
in the following situations:
ViewState
. ViewState
.
There are several ways to disable ViewState
at various levels:
ViewState
for a single control on a page, set the EnableViewState
property of the control to false
. ViewState
for a single page, set the EnableViewState
attribute in the @ Page
directive to false
. i.e. <%@ Page EnableViewState="false" %>
ViewState
for a specific application, use the following element in the Web.config file of the application: <pages enableViewState="false" />
ViewState
for all applications on a Web server, configure the <pages>
element in the Machine.config file as follows: <pages enableViewState="false" />
By enabling tracing for the page, you can monitor the ViewState
size for each control. You can use this information to determine the optimal size of the ViewState
or if there are controls in which the ViewState
can be disabled.
Avoid storing too much data in session variables, and make sure your session timeout is reasonable. This can use a significant amount of server memory. Keep in mind that data stored in session variables can hang out long after the user closes the browser. Too many session variables can bring the server on its knees. Disable session state, if you are not using session variables in the particular page or application.
EnableSessionState
attribute in the @ Page
directive to false
.i.e. <%@ Page EnableSessionState="false" %>
EnableSessionState
attribute in the@ Page
directive to ReadOnly
. i.e. <%@ Page EnableSessionState="ReadOnly" %>
<sessionState mode='Off'/>
<sessionState mode='Off'/>
Use the Server.Transfer
method to redirect between pages in the same application. Using this method in a page, with Server.Transfer
syntax, avoids unnecessary client-side redirection. Consider Using Server.Transfer
Instead of Response.Redirect
. However, you cannot always just replace Response.Redirect
calls with Server.Transfer
. If you need authentication and authorization checks during redirection, use Response.Redirect
instead of Server.Transfer
because the two mechanisms are not equivalent. When you use Response.Redirect
, ensure you use the overloaded method that accepts a Boolean second parameter, and pass a value of false
to ensure an internal exception
is not raised. Also note that you can only use Server.Transfer
to transfer control to pages in the same application. To transfer to pages in other applications, you must use Response.Redirect
.
The HTTP protocol is stateless; however, server controls provide a rich programming model that manage state between page requests by using ViewState
. However nothing comes for free, server controls require a fixed amount of processing to establish the control and all of its child controls. This makes server controls relatively expensive compared to HTML controls or possibly static text. When you do not need rich interaction, replace server controls with an inline representation of the user interface that you want to present. It is better to replace a server control if:
Alternatives to server controls include simple rendering, HTML elements, inline Response.Write
calls, and raw inline angle brackets (<% %>
). It is essential to balance your tradeoffs. Avoid over optimization if the overhead is acceptable and if your application is within the limits of its performance objectives.
Deeply nested hierarchies of controls compound the cost of creating a server control and its child controls. Deeply nested hierarchies create extra processing that could be avoided by using a different design that uses inline controls, or by using a flatter hierarchy of server controls. This is especially important when you use controls such as Repeater
, DataList
, and DataGrid
because they create additional child controls in the container.
Depending on how you choose to display data in a Web Forms page, there are often significant tradeoffs between convenience and performance. Always compare the pros and cons of controls before you use them in your application. For example, you can choose any of these three controls (DataGrid
, DataList
and Repeater
) to display data, it's your job to find out which control will provide you maximum benefit. The DataGrid
control can be a quick and easy way to display data, but it is frequently the most expensive in terms of performance. Rendering the data yourself by generating the appropriate HTML may work in some simple cases, but customization and browser targeting can quickly offset the extra work involved. A Repeater
Web server control is a compromise between convenience and performance. It is efficient, customizable, and programmable.
To optimize expensive loops, use For
instead of ForEach
in performance-critical code paths. Also do not rely on exception
s in your code and write code that avoids exception
s. Since exception
s cause performance to suffer significantly, you should never use them as a way to control normal program flow. If it is possible to detect in code a condition that would cause an exception
, do so. Do not catch the exception
itself before you handle that condition. Do not use exception
s to control logic. A database connection that fails to open is an exception
but a user who mistypes his password is simply a condition that needs to be handled. Common scenarios include checking for null
, assigning a value to a String
that will be parsed into a numeric value, or checking for specific values before applying math operations. The following example demonstrates code that could cause an exception
and code that tests for a condition. Both produce the same result.
1
'
Unnecessary use of exception
2
Try
3
value
=
100
/
number
4
Catch ex As Exception
5
value
=
0
6
End Try
7
8
'
Recommended code
9
If Not number
=
0
Then
10
value
=
100
/
number
11
Else
12
value
=
0
13
End If
14
Check for null
values. If it is possible for an object to be null
, check to make sure it is not null
, rather then throwing an exception
. This commonly occurs when you retrieve items from ViewState
, session state, application state, or cache objects as well as query string and form field variables. For example, do not use the following code to access session state information.
1
'
Unnecessary use of exception
2
Try
3
value
=
HttpContext.Current.Session(
"
Value
"
).ToString
4
Catch ex As Exception
5
Response.Redirect(
"
Main.aspx
"
, False)
6
End Try
7
8
'
Recommended code
9
If Not HttpContext.Current.Session(
"
Value
"
) Is Nothing Then
10
value
=
HttpContext.Current.Session(
"
Value
"
).ToString
11
Else
12
Response.Redirect(
"
Main.aspx
"
, False)
13
End If
Use a DataReader
object if you do not need to cache data, if you are displaying read-only data, and if you need to load data into a control as quickly as possible. The DataReader
is the optimum choice for retrieving read-only data in a forward-only manner. Loading the data into a DataSet
object and then binding the DataSet
to the control moves the data twice. This method also incurs the relatively significant expense of constructing a DataSet
. In addition, when you use the DataReader
, you can use the specialized type-specific methods to retrieve the data for better performance.
Allowing users to request and retrieve more data than they can consume puts an unnecessary strain on your application resources. This unnecessary strain causes increased CPU utilization, increased memory consumption, and decreased response times. This is especially true for clients that have a slow connection speed. From a usability standpoint, most users do not want to see thousands of rows presented as a single unit. Implement a paging solution that retrieves only the desired data from the database and reduces back-end work on the database. You should optimize the number of rows returned by the Database Server to the middle-tier web-server. For more information read this article to implement paging at the Database level. If you are using SQL Server 2000, please also look at this article.
To guarantee resources are cleaned up when an exception occurs, use a try
/finally
block. Close the resources in the finally
clause. Using a try
/finally
block ensures that resources are disposed even if an exception
occurs. Open your connection just before needing it, and close it as soon as you're done with it. Your motto should always be "get in, get/save data, get out." If you use different objects, make sure you call the Dispose
method of the object or the Close
method if one is provided. Failing to call Close
or Dispose
prolongs the life of the object in memory long after the client stops using it. This defers the cleanup and can contribute to memory pressure. Database connection and files are examples of shared resources that should be explicitly closed.
1
Try
2
_con.Open()
3
Catch ex As Exception
4
Throw ex
5
Finally
6
If Not _con Is Nothing Then
7
_con.Close()
8
End If
9
End Try
Before you deploy your application, disable tracing and debugging. Tracing and debugging may cause performance issues. Tracing and debugging are not recommended while your application is running in production. You can disable tracing and debugging in the Machine.config and Web.config using the syntax below:
1
<
configuration
>
2
<
system.web
>
3
<
trace enabled
=
"
false
"
pageOutput
=
"
false
"
/>
4
<
compilation debug
=
"
false
"
/>
5
</
system.web
>
6
</
configuration
>
By precompiled pages, users do not have to experience the batch compile of your ASP.NET files; it will increase the performance that your users will experience.
In addition, setting the AutoEventWireup
attribute to false
in the Machine.config file means that the page will not match method names to events and hook them up (for example, Page_Load
). If page developers want to use these events, they will need to override the methods in the base class (for example, they will need to override Page.OnLoad
for the page load event instead of using a Page_Load
method). If you disable AutoEventWireup
, your pages will get a slight performance boost by leaving the event wiring to the page author instead of performing it automatically.
In most cases you can get an additional performance boost by using compiled stored procedures instead of ad hoc queries.
Make sure you index your tables, and choose your indexes wisely. Try using Index Tuning Wizard and have it report to you what it thinks the best candidates for indexes would be. You don't have to follow all of its suggestions, but it may reveal things about your structure or data that will help you choose more appropriate indexes.