Building High-Performance ASP.NET Applications

As with any programming model, writing code to create an ASP.NET Web application has a number of pitfalls that can cause performance problems. The following guidelines list specific techniques that you can use to avoid performance bottlenecks.

The following guidelines list specific techniques that you can use to help maximize the throughput of ASP.NET Web applications. The guidelines are divided into the following sections:

1. Page and Server Control Processing

2. State Management

3. Data Access

4. Web Applications

5. Coding Practices

 

Page and Server Control Processing

The following guidelines suggest ways on how you can develop ASP.NET pages and controls that perform more efficiently.

Avoid unnecessary round trips to the server

While it is tempting to use the time- and code-saving features of the Web Forms page framework as much as you can, there are circumstances in which using ASP.NET server controls and postback event handling are inappropriate.

Typically, you need to create round trips to the server only when your application is retrieving or storing data. Most data manipulations can take place on the client in between these round trips. For example, validating user input from HTML forms can often take place on the browser before a user submits data to the server. In general, if you do not need to relay information to the server — to be stored in a database, for example — then you should not write code that creates a roundtrip.

If you develop custom server controls, consider having them render client-side code for uplevel browsers. By using server controls in this way, you can dramatically reduce the number of unnecessary hits to your Web server.

Use Page.IsPostback to avoid performing unnecessary processing on a roundtrip

If you write code that handles server control postback processing, you will sometimes want different code to execute the first time the page is requested than when a roundtrip occurs. Use the Page.IsPostBack property to conditionally execute code depending on whether the page is in response to a server control event.

For example, the following code demonstrates how to create a database connection and command, then binds the data to a DataGrid server control only if the page is requested for the first time.

 

Since the Page_Load event executes on every request, this code checks whether the IsPostBack property is set to false. If so the code executes; otherwise, it does not.

If you did not run such a check, the behavior of a postback page would not change. However, the code for the Page_Load event executes before server control events execute, but only the result of the server control events would render to the outgoing page. If this check were not run, processing would be performed for the Page_Load event and any server control events on the page. It can be easy to overlook this simple technique that can dramatically improve the response time for page request.

Use server controls in appropriate circumstances

Review your application code to make sure that your use of ASP.NET server controls is necessary. Even though they are extremely easy to use, server controls are not always the best choice to accomplish a task. In many cases, a simple rendering or databinding substitution will do. The following example demonstrates a situation in which using a server control is not the most efficient way to substitute values into the HTML sent to the client.

There are many other cases in which rendering or databinding are most efficient techniques to use, even when you use server control templates. However, if you want to programmatically manipulate a server control’s properties, handle server control events from it, or take advantage of view state preservation, then a server control would be appropriate.

Save server control view state only when necessary

Automatic view state management is a feature of server controls that enables them to re-populate their property values on a round trip without you writing any code. This feature does impact performance however, since a server control’s view state is passed to and from the server in a hidden form field. You should be aware of when view state helps you and when it hinders your page’s performance. For example, if you are binding a server control to data on every round trip, the saved view state will be replaced with new values obtained from the data binding operation, so disabling view state will save processing time.

To analyze the amount of view state used by the server controls on your page, enable tracing and look at the Viewstate column of the Control Hierarchytable. For information about tracing and how to enable it, see Asp.net Trace Functionality. 

State Management

The following guidelines suggest ways on how to manage state more efficiently.

Disable session state when you are not using it

Not all applications or pages require per-user session state, and you should disable it for any that do not.

To disable session state for a page, set the EnableSessionState attribute in the @ Page directive to false

Choose your session state provider carefully

ASP.NET provides three distinct ways to store session data for your application: in-process session state, out-of-process session state as a Windows Service, and out-of-process session state in a SQL Server™ database. Each has it advantages, but in-process session state is by far the fastest solution.

If you are only storing small amounts of volatile data in session state, it is recommended that you use the in-process provider. The out-of-process solutions are primarily useful if you scale your application across multiple processors or multiple computers or where data cannot be lost if a server or a process is restarted.

Data Access

The following guidelines suggest ways on how to access data more efficiently.

Use SQL Server™ stored procedures for data access

Of all the data access methods provided by the .NET Framework, SQL Server-based data access is the recommended choice for building high-performance, scalable Web applications.

When using the managed SQL Server™ provider, you can get an additional performance boost by using compiled stored procedures instead of ad-hoc queries. For information about using SQL Server™ stored procedures, see Using Stored Procedures with a Command.

Use the SqlDataReader class for a fast forward-only data cursor

The SqlDataReader class provides a means to read forward-only data stream retrieved from a SQL Server™ database.

When creating your ASP.NET application and situations arise that allow you to use it, the SqlDataReader class offers higher performance than the DataSetclass. This is because SqlDataReader uses the Tabular Data Stream ( TDS ) protocol to read data directly from a database connection. In addition, theSqlDataReader class implements the IEnumerable interface, which allows you to bind data to server controls as well.

For more information, see the SqlDataReader Class. For information how ASP.NET accesses data, see Accessing Data with ADO.NET.

Cache data and page output whenever possible

ASP.NET provides simple mechanisms for caching page output or data when they do not need to be computed dynamically for every page request. In addition, designing pages and data requests to be cached, particularly in areas of your site that you expect heavy traffic, can optimize the performance of those pages.

More than any feature of the .NET Framework, using the cache appropriately can make or break the performance of your site, sometimes by more than an order of magnitude. For information about how to cache page output and data requests, see ASP.NET Caching Features.

Web Applications

The following guidelines suggest ways on how to make your Web applications as a whole work efficiently.

If you have a large Web application, precompile it

Web application is batch-compiled on the first request for an application resource such as a page. If no page in the application has been parsed and compiled, the batch compilation feature will parse and compile all pages in the directory in chunks to provide better disk and memory usage. This feature gives ASP.NET a performance benefit, since it compiles many pages into a single assembly. Accessing a page from an assembly that is already loaded is faster than loading a new assembly per page. Note that if batch compilation of multiple pages into a single directory exceeds the number of seconds specified for the BatchTimeout property, a single page will be parsed and compiled so that the request can be processed quickly.

The disadvantage of batch compilation is that if the server receives many requests for pages that have not been compiled, performance can be poor while the Web server parses and compiles them. To solve this problem, you can precompile the application.

Recycle processes when running ASP.NET Web applications on Internet Information Services 5.0

By default, ASP.NET on IIS 5.0 will service requests using an out-of-process worker process. This feature has been tuned for fast throughput. Because of its features and advantages, running ASP.NET in an out-of-process worker process is recommended for production sites.

You should recycle processes periodically, for both stability and performance. Over long periods of time, resources with memory leaks and bugs can affect Web server throughput, and recycling processes cleans up memory from these types of problems. However, you should balance the need to periodically recycle with recycling too often, because the cost of stopping the worker process, reloading pages, and re-obtaining resources and data can override the benefits of recycling.

ASP.NET Web applications running on Windows Server 2003, which uses IIS 6.0, do not need to have the process model setting adjusted because ASP.NET will use the IIS 6.0 process model settings.

Adjust the number of threads per worker process for your application if necessary

The request architecture of ASP.NET tries to achieve a balance between the number of threads executing requests and available resources. The architecture allows only as many concurrently executing requests as there is CPU power available. This technique is known as thread gating. However, there are conditions in which the thread-gating algorithm does not work well. You can monitor thread gating in the Windows Performance monitor using the Pipeline Instance Countperformance counter associated with the ASP.NET Applications performance object.

When an ASP.NET Web page calls an external resource, such as when performing database access or XML Web service requests, the page request generally stops until the external resource responds, freeing the CPU to process other threads. If another request is waiting to be processed and a thread is free in the thread pool, the waiting request begins processing. The result can be a high number of concurrently executing requests and many waiting threads in the ASP.NET worker process or application pool, which hinders the Web server’s throughput, adversely affecting performance.

Consider enabling Web gardening on multiprocessor computers

The ASP.NET process model helps enable scalability on multiprocessor computers by distributing work to several processes, one per CPU, each with processor affinity set to a CPU. This technique is called web gardening, and can dramatically improve the performance of applications that rely extensively on external resources.

If your application uses a slow database server or calls COM objects that have external dependencies, to name only two possibilities, it can be beneficial to enable Web gardening for your application. However, you should test how well your application performs in a Web garden before you decide to enable it for a production Web site.

Disable debug mode

Always 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 significantly. For syntax information about setting the debug mode in the Web.configfile, see ASP.NET Configuration Sections.

Tune the configuration files for your Web server computer and for specific applications to suit your needs

By default, ASP.NET configuration is set to enable the widest set of features and to try to accommodate the most common scenarios. Some default configuration settings can be changed to improve the performance of your applications, depending on what features you use. The following list includes configuration settings you should consider:

  • Enable authentication only for applications that need it   By default, the authentication mode for ASP.NET applications is Windows, or integrated NTLM. In most cases it is best to disable authentication in the Machine.config file and enable it in the Web.config files only for applications that need it.
  • Configure your application to the appropriate request and response encoding settings   The ASP.NET default encoding is UTF-8. If your application uses only ASCII characters, configure your application for ASCII for a slight performance improvement.
  • Consider disabling AutoEventWireup for your application   Setting the AutoEventWireup attribute to false in the Machine.config file means that the page will not bind page events to method based on a name match (for example, Page_Load). If you disable AutoEventWireup, your pages will get a slight performance boost by leaving the event wiring to you instead of performing it automatically.

    If you want to handle page events, you will need to override the methods in the base class (for example, you will need to override the OnLoad method of the Page object for the page load event instead of using a Page_Load method).

  • Remove unused modules from the request-processing pipeline   By default, all features are left active in the HttpModules node in your server computer’s Machine.config file. Depending on which features your application uses, you may be able to remove unused modules from the request pipeline to get a small performance boost. Review each module and its functionality and customize it to your needs.

    For example, if you do not use session state and output caching in your application, you can remove each from the HttpModules list so that requests do not have to invoke these modules without performing any other meaningful processing.

     

    Coding Practices

    The following guidelines suggest ways on how to write code that work more efficiently.

    Avoid relying on exceptions in your code

    Since exceptions 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, you should do that instead of waiting to catch the exception itself before handling that condition. Common scenarios include checking for null, assigning 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 you to test for a condition that would do the same thing.

    // consider changing this…

 try { result = 100 / num; } catch ( Exception e ) { result = 0; } // to this… if ( num != 0 ) result = 100 / num; else result = 0;

  • Use early binding in Visual Basic.NET or JScript code

    One of the reasons that developers love Visual Basic, VBScript, and JScript is their "typeless" nature. Variables may be created simply by using them and need no explicit type declaration. When assigning from one type to another, conversions are performed automatically as well. This can be a blessing and a curse, since late binding is a very expensive convenience in terms of performance.

    The Visual Basic language now supports type-safe programming through the use of a special Option Strict compiler directive. For backward compatibility purposes, ASP.NET does not enable this option by default. For optimal performance, however, it is highly recommended that you enable this option on your pages. To enable Option Strict, include a Strict attribute in the @ Page directive or, for a user control, the @ Control directive. The following example demonstrates setting this attribute and code that would and would not cause a compiler error.

     

    Use the common language runtime’s garbage collector and automatic memory management appropriately

    Be careful about using too much memory per request, such as storing large objects or sets of data in memory, because the garbage collector will have to do more work more often. Also, do not keep unnecessary references to objects in your code when you no longer need the object, because the garbage collector cannot free resources if they are still being referenced.

    Try to avoid using objects with Finalize methods, since they will entail more work for the garbage collector at a later time. In particular, never free resources in a call to Finalize, because the resource could consume memory until the garbage collector calls its Finalize method. This last problem often ruins performance in Web server environments, since it can be easy to exhaust the availability of a given resource while waiting for Finalize to run.

    Port call-intensive COM components to managed code

    The .NET Framework provides a remarkably easy way to interoperate with traditional COM components. The benefit is that you can start taking advantage of the new platform while preserving your existing investments. However, there are some circumstances where the performance cost of keeping your old components is greater than the cost to migrate your components to managed code. Every situation is unique, and the best way to decide whether you need to port a component is to run performance measurements against your Web site. In general though, the performance impact of COM interoperability is proportional to the number of function calls made, or data marshaled, from unmanaged to managed code. It is recommended that you investigate porting to managed code any COM component that requires a high volume of calls in order to interact. This will allow you to benefit from the performance gains of the .NET platform. Alternatively, you might consider redesigning your component to require fewer calls or marshal more data during a single call.

    Avoid single-threaded apartment (STA) COM components

    By default, ASP.NET does not allow STA COM components to run in a page. To run them, you must include the ASPCompat=true attribute in the @ Pagedirective in the .aspx file. This switches the thread pool used for page execution to an STA thread pool, while also making the HttpContext and other built-in objects available to the COM object. Avoiding STA COM components is a performance optimization because it avoids any call marshaling from multithreaded apartment ( MTA ) to STA threads.

    If you must use an STA COM component, avoid making numerous calls during an execution and try to send as much information as possible during each call. Also, avoid creating STA COM components during the construction of the page. For example, in the following code, the SampleSTAComponent would be instantiated at page construction time, which is created from a thread that is not the STA thread that runs the page. This can have an adverse performance impact, since it will require marshaling between MTA and STA threads to construct the page.

    Use System.Text.StringBuilder for String concatenation

    Web applications often need to perform extensive String manipulation and using standard string operators is a very poor performance choice. The StringBuilder class offers higher performance when you want to concatenate strings.

 

, , ,

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Share to Facebook Share to Twitter Stumble It Share on Tumblr Digg More...