……………………………………………….Expertise in .NET Technologies

Best Practices for ASP.NET

Posted by Ravi Varma Thumati on December 4, 2009


Although the designers of Microsoft® ASP.NET have done an excellent job in preserving backward compatibility with ASP applications, you need to be aware of a few best practices as follows.

1.      Code Blocks: Declaring Functions and Variables

In ASP, you can declare subroutines and global variables in between your code delimiters.


Dim X

Dim str

Sub MySub()

Response.Write “This is a string.”

End Sub


In ASP.NET, this is no longer allowed. You must instead declare all of your functions and variables inside a <script> block.

<script language = “vb” runat = “server”>

Dim str As String

Dim x, y As Integer

Function Add(I As Integer, J As Integer) As Integer

Return (I + J)

End Function


2.      Avoid Using default properties

The default properties are no longer allowed. Accessing your properties explicitly isn’t really that hard to do anyway. It will make your code more readable and also save you time in porting in the future.

3.      Remove code from content as much as possible

You should separate your code from HTML content. Clean up functions that mix code and script throughout a function body. Doing so puts you in a much better position to leverage code-behind as this is the ideal model under ASP.NET anyway.

4.      Mixing Programming Languages

In ASP.NET, you can use any Common Language Runtime-compliant language. C#, Visual Basic .NET, and JScript are the current languages provided by Microsoft. Note that the language is Visual Basic .NET instead of VBScript. This is because VBScript does not exist in the .NET platform. It has been fully subsumed by Visual Basic .NET.

Although you are free to pick any of these languages, it is important to note that you cannot mix languages on the same page as you could do in ASP. It is certainly possible to have Page1.aspx of your application contain C# code while Page2.aspx of the same application contains Visual Basic .NET code. You just cannot mix them together in a single page.

New Page Directives

In ASP.NET, you are now required to place the Language directive with a Page directive, as follows:

<%@ Page CodeBehind=”test.aspx.vb”%>

<%@QutputCache Duration=”60″ VaryByParam=”none” %>

You can have as many lines of directives as you need. Directives may be located anywhere in your .apsx file but standard practice is to place them at the beginning of the file.

5.      Structured Error Handling

Errors in web applications can be broadly classified into two categories system errors and business logic errors. The first type of errors might be because of network crashes, database crashes or server down-times. The second type of errors is related to particular business rules. These errors vary based on application under consideration.

All of these errors call for a robust and user-friendly error handling techniques for your applications.

The various options available for us for handling errors in are:

  • Code in such a way that possibility of error is less
  • Trapping errors as and when they occur
  • Throw errors wherever appropriate to assist unified error handling
  • Handle errors via Application_Error event in global.asax
  • Provide custom error pages for predefined IIS errors
  • Provide custom error pages for business errors

Let us dissect each of the options in detail.

  • Code in such a way that possibility of error is less

As the saying goes – prevention is better than cure, you should try to avoid error conditions as far as possible. Consider an example suppose you want to perform some mathematical calculation of two numbers supplied by the user. You know that if you divide a number by 0 an error is going to occur. You can avoid such errors with a simple if condition. This will not only prevent further errors but also reduce burden from your error handling system.

  • Using Try…Catch to trap exceptions

As stated previously, you should be prepared to handle unexpected conditions like network failures, database crashes and the like. Languages like C# and VB.NET provide a special construct Try…Catch for trapping such errors. In .NET terminology errors are referred as exceptions indicating that some thing abnormal has happened. Following code fragment shows how to use this construct:


Dim MyObject As Object
Response.Write(“Call To Object Succeeded”)

Catch NRE As NullReferenceException
Response.Write(“Null Reference Exception<BR>”)

Catch DefaultExcep As Exception
Response.Write(“Error Occured, Unknown Orgin”)

Response.Write(“Caught Exception”)
End Try

Here, we have placed the code that might throw an exception into the try block. If any exception occurs here the control will shift to the catch block. Catch block allows you to filter your exception. In above example we have used general Exception class however, you can test for a specific exception as well. The finally block is executed in normal as well as abnormal conditions. This block is typically used to perform clean up task of the method like closing database connection or re-initialize certain variables.

  • Throwing exceptions

While developing complex systems you may develop your own exception classes. Custom exception classes are nothing but classes derived from System.Exception or System.ApplicationException classes. Why one will want to throw an exception? One reason is to bring the uniformity in the error handling techniques. Also, this way you can identify business error conditions in code itself rather than relaying on some database stored error codes. You will also be able to provide much detailed and user-friendly information to the users. You can throw exceptions using throw keyword.

The following example shows how:

If some_condition

throw new Exception(“Custom error”);

End if

However, keep in mind that throwing an exception is an expensive task. You should use your judgment while using this technique.

  • Using Application_Error event

Let us now begin with error handling techniques specific to ASP.NET. The global.asax file contains Application_Error event that gets fired every time an unhandled exception occurs in the web application. This is the ideal place to log your unhandled errors. The following code shows sample usage of this event:

Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)

Response.Write(“Unexpected error occured ! <br>”  & Server.GetLastError().Message);


End Sub

The Server.GetLastError() returns an Exception class that gives details about the exception. Note that this event will be fired only for unhandled exceptions i.e. exceptions not trapped using Trycatch, error page, custom error page or any other techniques.

  • Using ErrorPage

In case of unhandled errors you will get default ASP.NET error page giving information about the error. You will agree that this page is far from being user friendly. You can provide much better user experience by the use of custom error pages. The Page class has a property called as ErrorPage that can contain url of a HTML/ASPX page that will be displayed if any unhandled exception occurs in your code.


You can set this property either via properties windows of VS.NET or via code. Note that only unhandled exceptions from the page will cause the error page to be displayed.

In order to use the error page, follow these steps:

In the web.config file, turn on the customErrors mode as shown below:

<customErrors mode=”On” />

To the web forms in the project, set its errorPage property to errpage.aspx. Add a web form named errpage.aspx to the project

In the web forms there will be code like the following that can throw an exception.

conn.ConnectionString = “user;password=;xyz,initial catalog=pubs;”


comm.Connection = conn

comm.CommandType = CommandType.Text

comm.CommandText = “select au_id,au_lname,au_fname from authors”

Return comm.ExecuteReader(CommandBehavior.CloseConnection)

Now, run the application and enter some invalid value for database connection string. You will find that the errpage.aspx is shown.

Note how the page causing error is passed to the error page via query string.

  • Using Custom error pages

There are some errors that are not in control of developers. Page not found, internal server errors are some examples. Traditionally developers or administrators used to put custom error pages for such errors using IIS snap-in. ASP.NET allows you to do this via web.config.

This means that you can customize error pages without going to IIS snap-in and also change them easily in future. Setting custom error pages requires you to modify <customErrors> section of web.config file.

Following markup shows one such example:

<customErrors mode=”On” defaultRedirect=”errpage.aspx”>

<error statusCode=”404″ redirect=”filenotfound.aspx” />


We saw various error handling techniques that can be used in ASP.NET. The techniques like Trycatch are language features of languages like C# and VB.NET and can be used in general programming also. The web.config plays important role in configuring the custom error pages for your application.

6.      String Concatenation

The good news is that regardless of what technique you use to concatenate strings in ASP.NET it will be faster than it was in classic ASP. That said there are two common ways that strings are usually concatenated using the .NET Framework/VB.NET. One is to use the & character to concatenate two strings like so:

Dim myOutputString As String = “My name is”

Dim myInputString As String = ” Alex”

myOutputString = myOutputString & myInputString


The second technique makes use of the StringBuilder class. The StringBuilder class will look foreign to those of you who are new to ASP.NET. To concatenate strings using the StringBuilder class you would use code such as this:

Dim myStringBuilder As New StringBuilder(“My name is”)

Dim myInputString As String = ” Alex”



Now, you will probably not notice a performance difference when concatenating less than five times (as concatenation is often done in a loop of some kind). In fact, you may see the & technique of concatenation peform a little better than the StringBuilder class when performing fewer than five concatenations. The “best practice” tip to take away from this section though is that the StringBuilder class will majorly outperform the & character when doing five plus concatenations.

7.      Usage of ViewState

Depending on the size of the viewstate, transmitting it across a network can entail a performance hit. You can check the viewstate for any control, or the complete page, by turning on tracing using a Page directive:

<%@Page Trace=”true” … %>

To disable viewstate maintenance for a page, use the following Page directive:

<%@Page EnableViewState=”false” … %>

To disable viewstate maintenance for a single control, use the EnableViewState property:

<ASP: DataGrid EnableViewState=”false” … runat=”server”/>

To disable viewstate maintenance for an entire application, change the setting in web.config:

<Pages enableviewstate=”false” …/>

8.      Manage your Session State

You should only use sessions when they are actually required for the application. Turn them off in any pages that don’t require access to them. Alternatively, use read-only session state where you don’t need to update the values.

To disable session state maintenance for a page, use the Page directive:

<%@Page EnableSessionState=”false” …%>

To disable session state maintenance for an entire application, change the setting in Web.Config:

<sessionState mode=”off” />

<pages enableSessionState=”false” … />

To specify read-only session state maintenance for a page, use the Page directive:

<%@Page EnableSessionState=”ReadOnly” … %>

To specify read-only session state maintenance for an entire application, change the setting in Web.Config:

<pages enableSessionState=”ReadOnly” … />

You configure your state management options in the <sessionState> section of your web.config file as follows:




sqlConnectionString=”data source=;user id=sa;password=”    cookieless=”false”



The mode attribute specifies where you would like to store your state information. Your options are Inproc, StateServer, SqlServer, or Off.

Session State Storage Information

Option Description
Inproc Session state is stored locally on this server (ASP style).
StateServer Session state is stored in a state service process located remotely or potentially locally.
SqlServer Session state is stored in a SQL Server database.
Off Session state is disabled.

StateConnectionString and sqlConnectionString obviously come into factor if you use one of these other options. You can only use one storage option per application.

Where possible, use the default in-process session management. The out-of-process state service can produce a performance hot of 20 percent over the in-process session manager, and the remote SQL server state management session adds around another 50 percent performance hot over out-of-process session state management – use it only for web form.

9.      Reuse work by Caching

ASP.NET allows you to cache the entire response content for dynamic pages on HTTP 1.1 capable mechanisms, including browsers, proxy servers, and the origin Web server where your application resides. This provides a powerful way for you to increase the performance of your Web applications. Called output caching, it allows subsequent requests for a particular page to be satisfied from the cache so the code that initially creates the page does not have to be run upon subsequent requests. Using this technique to cache your site’s most frequently accessed pages can increase your Web server’s throughput, commonly measured in requests per second, substantially.

You can use the caching feature by including the @ OutputCache directive in the .aspx file for the page. The @ OutputCache directive can meet nearly all the common needs you may have when you want to cache a page’s output. The following directive, when included in an .aspx file, sets an expiration of 60 seconds for the cached output of a dynamically generated page.

<%@ OutputCache Duration=”60″ VaryByParam=”None” %>

CAUTION When you use the @ OutputCache directive, the Duration and VaryByParam attributes are required. If you do not include them, a parser error occurs when the page is first requested. If you do not want to use the functionality that the VaryByParam attribute provides, you must set its value to none.

10. Use server controls only when appropriate

If you need to access HTML element’s properties, methods or events in server-side code, you have to declare it as server-side code. For example, following situations do not require a server control.

q       When the element is only used to run some client-side script, for example, a button that opens a new browser window, or that interacts with a client-side ActiveX control or java applet, or that calculates some value for display in the page using DHTML or an alert dialog

q       When the element is a hyperlink that opens a different page or URL and there is no need to process the values for the hyperlink on the server.

q       Any other times when access to the element’s properties, methods or events in server-side code is not required.

A page containing server controls will take a performance hit compared to one that does not use server controls, perhaps as much as 30 percent. However, using code to set or access the element content directly will also cause a performance hit, so if you do need to access the element programmatically (even just to set the text or value), use a server control for that element.

11. Use a DataReader instead of Dataset

The only times that a DataSet muse be used in preference to a DataReader are:

q       When the data will be remoted (disconnected) to the client or a remote application or component – for example, when using a Web Service that returns a DataSet.

q       When more than one set of rows must be stored (and optionally the relationships between them).

The DataReader can be used as the source for data binding controls if required.

12. Resource leak caused by not closing database connections and/or DataReaders

In VB 6 and VBScript, it was a best practice to always close objects (especially precious resources like connections, recordsets, etc.) and to always set them equal to nothing. Well, that is still partially true. We still need to close connection objects when we are done with the database connection. We also need to remember to close our DataReader. Here are a couple examples that demonstrate how the database connection and/or DataReader object should be closed.
Here we are using the CommandBehavior.CloseConnection enumeration which will close the connection as soon as all of the data as been streamed into the SqlDataReader. So, we don’t have close the connection. Instead, we need to close the SqlDataReader in our Finally segment.

Dim myConnection As SqlConnection = new SqlConnection(ConfigurationSettings.AppSettings(“DSN_pubs”))

Dim myCommand As SqlCommand = new SqlCommand(“Select pub_id, pub_name From publishers”, myConnection)

Dim myDataReader As SqlDataReader



myDataReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection)

DropDownList1.DataSource = myDataReader


Catch myException As Exception

Response.Write(“An error has occurred: ” & myException.ToString())


If Not myDataReader Is Nothing Then

‘Notice that we close the DataReader here!


End If

End Try

Here we are directly passing the results of the ExecuteReader method to the DataSource property of the DropDownList. So, we need to close the connection, which we do in the Finally segment. Before we call the Close method we check to make sure the connection is open because attempting to close a connection that is not open will cause an exception to be thrown.

Dim myConnection As SqlConnection = new SqlConnection(ConfigurationSettings.AppSettings(“DSN_pubs”))

Dim myCommand As SqlCommand = new SqlCommand(“Select pub_id, pub_name From publishers”, myConnection)

Dim myDataReader As SqlDataReader



‘Notice that we are not using the CommandBehavior.CloseConnection enum in this example

DropDownList1.DataSource = myCommand.ExecuteReader()


Catch myException As Exception

Response.Write(“An error has occurred: ” & myException.ToString())


If Not myConnection Is Nothing AndAlso ((myConnection.State And ConnectionState.Open) = ConnectionState.Open) Then


End If

End Try

13. Use SQL (TDS) classes for Data Access

There are two sets of objects for accessing a data source:

q       Objects prefixed OleDb (from the System.Data.OleDb namespace) use an OLE-DB provider to access that data store.

q       Objects prefixed Sql (from the System.Data.SqlClient namespace) use the Microsoft SQL Server Tabular Data Stream (TDS) interface to access that data store.

The Sql prefixed objects are much faster and more efficient, and should always be used where you know that the data store will be Microsoft SQL server 7, 2000 or above. Both OleDb and Sql objects automatically provide connection pooling.

14. Use Data Binding where possible

Traditionally, ASP has been used to iterate through a rowset extracting values and placing them in the page. In ASP.NET, the list controls can this automatically through data binding, and provide a huge performance increase.

Compared to using ASP 3.0 with ADO to create an HTML table explicitly from a recordset, ASP.NET with a data-bound DataList control fed by a DataReader object using the OleDb data provider can be three times faster. Switch to the Sql TDS data provider and it can be up to five times faster.

15. Use Early Binding for Better performance

Early Binding provides much better performance than late binding. To ensure that only early binding is used, always include the Option Explicit statement in code to force variables to be pre-declared. By default, ASP.NET pages are automatically compiled with the equivalent to Option Explicit set.

Also, always specify a data type for variables when they are declared. This provides strong typing of variables for best performance. For example, use:

Dim intThis as Integer

Rather than:

Dim intThis

It’s also worth using Option Strict where possible to enforce strict variable typing. This means that variables must be explicitly cast to the correct data type for each operation that requires a type conversion. In ASP.NET enable strict compilation


<%@Page Language=”VB” Strict=”true” … %>

16. Use the new Request and Response Objects

In ASP.NET request and response objects have been extended to provide many new features that can improve performance. For example, to write the contents of a disk file into a page, use a new response.writefile method rather then opening the file, reading it from disk and writing it to the response.

Finally, avoid the ServerVariables collection where possible by using the new Request properties like Request.Url, Request.Referrer, Request.PhysicalPath, Request.UserAgent and so on.

17. Use the Web.Config/Machine.Config file to store application wide data

While you can use the web.config file to store your database connection string it is more secure to store the database connection string in the machine.config file. The machine.config file contains machine-wide settings for various parts of the .NET Framework. Most of the settings stored in the machine.config file pertain to ASP.NET.

Well, let’s look at the most common situation — the single web site. If you’re building a single web site, and it has a single database supporting it, then your best bet is to store your connection information in your Web.config file. It is then very easy to retrieve this information from any of your ASP.NET pages, using the following syntax:


Dim connstring as string

connstring = ConfigurationSettings.AppSettings(“ConnectionString”)

To add support for this to your Web.Config, you need to add an AppSettings section, like this one:


<add key=”ConnectionString” value=”(your connection string)” />


For larger applications, which have dozens of different web applications all relying on the same database, there are several options. Since all of the columnist websites are subwebs of the root site, the easiest thing to do is to store the global config information in the root web’s Web.config file.

For a server that has many different sites all using the same database (i.e. different IP addresses and domain names, not subwebs), the best solution if you want to keep all of the connection information in one place is to use the machine.config file for the server.

There is an appSettings section already in the machine.config file that serves this purpose. Whenever possible, the web.config file should be used for storing sensitive application information, and remember that all sites inherit from the machine.config, and subwebs inherit from parent webs, so store your connection info as high up in the tree hierarchy as necessary to allow all the sites that need it to access it.

  • Authentication

ASP.NET Authentication Options

Type Description
Windows ASP.NET uses Windows authentication.
Forms Cookie-based, custom login forms.
Passport External Microsoft provided Passport Service.
None No authentication is performed.

These are the same options you have in ASP, with the exception of the new Passport authentication option. As an example, the following configuration section enables Windows-based authentication for an application:



<authentication mode=”Windows”/>



  • Authorization

Once your users have been authenticated, you can focus on authorizing what resources you would like them to have access to. The following sample shows access being granted to “jkieley” and “jstegman,” while everyone else is denied access.


<allow users=”NORTHAMERICA\jkieley, REDMOND\jstegman”/>

<deny users=”*”/>


18. Use ASP.NET’s Trace feature to debug instead of using Response.Write

A lot of classic ASP developers have got really good at using Response.Write to debug their applications. Using Response.Write to debug class ASP applications was a necessary evil. ASP.NET provides a new debugging facility in the Trace class. Tracing is much cleaner than Response.Write and can be turned on and off by simply changing a single setting in either the page or the web.config file (never again will you have to remember to comment out those Response.Write statements!).

In addition to custom debugging information, tracing also provides us with a snapshot of the Form, Querystring, Headers, Cookies, and Session collections. Also viewable in the trace information is the page’s control tree and the web server variables.

We can turn tracing on at the page level (using the Trace attribute of the @Page directive) or at the application level in our web.config file. Page level tracing displays trace information for a single page and the trace information is simple tracked onto the output of the page.

Application level tracing works a little bit different than page level tracing. Instead of displaying trace information on each and every page, application level tracing provides trace information for a user definable number of requests. The localOnly attribute determines whether trace information is viewable (via a browser) remotely or only from the console of the web server. The number of requests available is set using the requestLimit attribute (shown above) of the trace element.

Each pages trace information is stored in memory and is viewable by pointing a browser at

Because trace information is stored in memory, it is good practice to keep the number of requests low (less than 20).

Here is how you can turn tracing on or off in a single ASP.NET page:

<%@ Page Trace=”True” %>

We can also turn tracing on or off for the entire ASP.NET application using syntax similar to the following (in our web.config file):



<trace enabled=”true” requestLimit=”10″ localOnly=”false”/>



Then, in our ASP.NET page, we can use code such as the following to write custom trace (debug) information out to the page:

Trace.Write(“This is some custom debugging information”)


Trace.Write(“This is is my variable and it’s value is:” & myVariable.ToString())

19. Use Page.IsPostBack to avoid extra round trips to     the server

If you are handling server control postbacks, you often need to execute different code the first time the page is requested from the code you do use for the round trip when an event is fired. If you check the Page.IsPostBack property, your code can execute conditionally, depending on whether there is an initial request for the page or a responce to a server control event. It might seem obvious to do this, but in practice it is possible to omit this check without changing the behavior of the page. For example:

<script runat=”server”>

Public ds As DataSet

Sub Page_Load(sender As Object, e As EventArgs)

‘ …set up a connection and command here…

If Not (Page.IsPostBack)

Dim query As String = “select * from Authors where FirstName like ‘%JUSTIN%'”

myCommand.Fill(ds, “Authors”)


End If

End Sub

Sub Button_Click(sender As Object, e As EventArgs)

Dim query As String = “select * from Authors where FirstName like ‘%BRAD%'”

myCommand.Fill(ds, “Authors”)


End Sub


<form runat=”server”>

<asp:datagrid datasource='<%# ds.Tables[“Authors”].DefaultView %>’ runat=”server”/><br>

<asp:button onclick=”Button_Click” runat=”server”/>


<script runat=”server”>

public var ds:DataSet;

function Page_Load(sender:Object, e:EventArgs) : void {

// …set up a connection and command here…

if (!Page.IsPostBack) {

var query:String = “select * from Authors where FirstName like ‘%JUSTIN%'”;

myCommand.Fill(ds, “Authors”);




function Button_Click(sender:Object, e:EventArgs) : void {

var query:String = “select * from Authors where FirstName like ‘%BRAD%'”;

myCommand.Fill(ds, “Authors”);




<form runat=”server”>

<asp:datagrid datasource='<%# ds.DefaultView %>’ runat=”server”/><br>

<asp:button onclick=”Button_Click” runat=”server”/>


20. Storing COM Components

One thing to keep in mind is that if you rely on storing
references to your legacy COM components in the Session or Application object, you cannot use the new state storage mechanisms (StateServer or SqlServer) within your application. You will need to use Inproc. This is due, in part, for the need of an object to be self-serializable in .NET terms, something that COM components obviously cannot do. New, managed components you create, on the other hand, can do this relatively easily and thus can use the new state storage models.

21. Disable Debug Mode

Always remember to disable debug mode before deploying a production application or conducting any performance measurements. If debug mode is enabled, the performance of your application can suffer a great deal.

How to speed up your application loading time?


Use Properties Instead of Raw Data

With the addition of properties as language elements, there is absolutely no reason to declare data elements with any access level greater than private. Because client code will view properties as data elements, you don’t even lose the convenience of working with simple data elements in classes. In addition, using properties gives you more flexibility and more capabilities. Properties provide better encapsulation of your data elements. Properties let you make use of lazy evaluation to return data. Lazy evaluation means that you can calculate the data value only when it is requested from a client, rather than keep it around all the time.

Finally, properties can be virtual. They can even be abstract. You can also declare properties in interfaces.

There is yet another maintenance reason: Even though they are accessed the same way, if you change a data element to a property, client code that had been compiled using the data element will no longer work with the version using the property. In fact, you can even use properties in Web services for those values you want to serialize:

    private int TheMonth = 0;

    [XmlAttribute ("Month")]
    public int Month {
      get {
        return TheMonth;
      set {
        TheMonth = value;

Simply put, properties let you make your entire data elements private.

Pay Attention to Initialization Order

The C# language adds the concept of initializers on member variable declarations. These initializers get executed before the body of the constructor gets executed. In fact, variable initializers get executed before the base class’s constructor gets executed.

For this reason, make sure any variable initializers do not make use of base class data; the base class has not yet been constructed.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: