How To: Scale .NET Applications

Overview
Scalability refers to the ability of an application to continue to meet its performance objectives with increased load. Typical performance objectives include application response time and throughput. When measuring performance, it is important to consider the cost at which performance objectives are achieved. For example, achieving a sub – second response time objective with prolonged 100% CPU utilization would generally not be an acceptable solution.
This How To is intended to help you make informed design choices and tradeoffs that in turn will help you to scale your application. An exhaustive treatment of hardware choices and features is outside the scope of this document.
After completing this How To, you will be able to:

  • Determine when to scale up versus when to scale out.
  • Quickly identify resource limitation and performance bottlenecks.
  • Identify common scaling techniques.
  • Identify scaling techniques specific to .NET technologies.
  • Adopt a step-by-step process to scale .NET applications.
  • Scale Up vs. Scale Out

    There are two main approaches to scaling:
    Scaling up. With this approach, you upgrade your existing hardware. You might replace existing hardware components, such as a CPU, with faster ones, or you might add new hardware components, such as additional memory. The key hardware components that affect performance and scalability are CPU, memory, disk, and network adapters. An upgrade could also entail replacing existing servers with new servers.
    Scaling out. With this approach, you add more servers to your system to spread application processing load across multiple computers. Doing so increases the overall processing capacity of the system.

    Pros and Cons
    Scaling up is a simple option and one that can be cost effective. It does not introduce additional maintenance and support costs. However, any single points of failure remain, which is a risk. Beyond a certain threshold, adding more hardware to the existing servers may not produce the desired results. For an application to scale up effectively, the underlying framework, runtime, and computer architecture must also scale up.

    Scaling out enables you to add more servers in the anticipation of further growth, and provides the flexibility to take a server participating in the Web farm offline for upgrades with relatively little impact on the cluster. In general, the ability of an application to scale out depends more on its architecture than on underlying infrastructure.

    When to Scale Up vs. Scale Out
    Should you upgrade existing hardware or consider adding additional servers? To help you determine the correct approach, consider the following:

  • Scaling up is best suited to improving the performance of tasks that are capable of parallel execution. Scaling out works best for handling an increase in workload or demand.
  • For server applications to handle increases in demand, it is best to scale out, provided that the application design and infrastructure supports it.
  • If your application contains tasks that can be performed simultaneously and independently of one another and the application runs on a single processor server, you should asynchronously execute the tasks. Asynchronous processing is more beneficial for I/O bound tasks and is less beneficial when the tasks are CPU bound and restricted to a single processor. Single CPU bound multithreaded tasks perform relatively slowly due to the overhead of thread switching. In this case, you can improve performance by adding an additional CPU, to enable true parallel execution of tasks.
  • Limitations imposed by the operating system and server hardware mean that you face a diminishing return on investment when scaling up. For example, operating systems have a limitation on the number of CPUs they support, servers have memory limits, and adding more memory has less effect when you pass a certain level (for example, 4 GB).
  • Load Balancing
    There are many approaches to load balancing. This section contains a discussion of the most commonly used techniques.

    Web Farm
    In a Web farm, multiple servers are load balanced to provide high availability of service. This feature is currently only available in Windows® 2000 Advanced Server and Datacenter Server. Figure 1 illustrates this approach.

    Load balancing in a Web farm

    Load balancing in a Web farm

     

    for more see: http://msdn.microsoft.com/en-us/library/ms979199.aspx

    Performance Comparison: .NET Remoting vs. ASP.NET Web Services

    Introduction

    ASP.NET Web services and .NET Remoting provide a full suite of design options for cross-process communication in distributed applications. In general, ASP.NET Web services provide the highest levels of interoperability with full support for WSDL and SOAP over HTTP, while .NET Remoting is designed for common language runtime type-system fidelity and supports additional data format and communication channels. For more information, see ASP.NET Web Services or .NET Remoting: How to Choose.

    This article focuses on comparing relative performance of these techniques.

    ASP.NET Web Services

    ASP.NET provides a Microsoft® IIS-hosted infrastructure that supports industry standards such as SOAP, XML, and WSDL. Although.NET Remoting supports IIS hosting and SOAP over HTTP, ASP.NET is designed to provide the highest level of SOAP interoperability including support for SOAP Section 5 and document/literal.

    ASP.NET can leverage the features available with IIS, such as security and logging. IIS hosting is also robust in that it will re-spawn Aspnet_wp.exe if it terminates. Also, ASP.NET Web services are much easier to create and consume than services exposed using .NET Remoting because configuration is simplified both at the server and client.

    For more details, see Building XML Web Services Using ASP.NET in the .NET Framework Developer’s Guide.

    .NET Remoting

    .NET Remoting is more versatile and extensible in terms of enabling communication between objects using different transport protocols and serialization formats. TCP, HTTP, and custom protocols are supported as are Binary, SOAP, and custom formats. Multiple-object creation and lifetime modes are supported including Singleton, SingleCall, and Client-Activated. Remoting requires a host process, which can be IIS, or a Microsoft® Windows service or executable written in .NET.

    A .NET Remoting object using the SOAP formatter can be exposed as an XML Web service when hosted in IIS with ASP.NET. Since the payload is encoded in SOAP over HTTP, any client that supports the SOAP Encoding format can access the objects over the Internet. Another advantage of using the HTTP protocol is that it generally passes unobstructed across most firewalls. The TCP channel and the Binary formatter can be employed in an intranet environment where both the server and client are running on the .NET Framework. This approach is optimized for performance since raw sockets are used to transmit data across the network using a custom protocol that is more efficient than HTTP. Though this approach offers excellent performance in a closed environment, it cannot be employed in cross-platform scenarios where the client is not running the .NET Framework.

    IIS hosting provides secure communication for wire-level protection using Secure Sockets Layer (SSL), and you can also leverage IIS and ASP.NET authentication and authorization. The TCP channel as well as the HTTP channel with non-IIS hosting do not support secure socket transmission, so data is transmitted in clear text. You are required to implement your own security if you are using the TCP channel or the HTTP channel hosted in processes other than IIS.

    For more details, please refer to the .NET Remoting Overview in the .NET Framework Developer’s Guide.

    Conclusion

    As these tests demonstrate, the various design choices available with ASP.NET Web services and .NET Remoting carry varying amounts of overhead and therefore have vastly different performance characteristics. The size of data being passed is also significant and multiplies the differences between the other design choices. This comparison covers only stateless, synchronous remote procedure calls and does not cover the performance implications of authentication, authorization, and data privacy, which are other significant factors affecting the performance of distributed applications.

    Though both the .NET Remoting infrastructure and ASP.NET Web services can implement inter-process communication, each is designed with a particular level of expertise and flexibility in mind to benefit a different target audience. If your application needs interoperability with other platforms or operating systems, you would be better off using ASP.NET Web services, as they are more flexible in that they support SOAP section 5 and Document/Literal. On the other hand, use .NET Remoting when you need the richer object-oriented programming model. See ASP.NET Web Services or .NET Remoting: How to Choose for details. In scenarios where performance is the main requirement with security and process lifecycle management is not a major concern, .NET Remoting TCP/Binary is a viable option; however, keep in mind that you can increase the performance of IIS-hosted implementations by adding a few more machines into the system, which may not be possible when using a .NET Remoting TCP/Binary implementation.

    (sursa: http://msdn.microsoft.com/en-us/library/ms978411.aspx)

    Improving Managed Code Performance

    The CLR consists of a number of components that are responsible for managed code execution. These components are referred to throughout this chapter, so you should be aware of their purpose. Figure 5.1 shows the basic CLR architecture and components.

    CLR architecture

    CLR architecture

    The way you write managed code significantly impacts the efficiency of the CLR components shown in Figure 5.1. By following the guidelines and techniques presented in this chapter, you can optimize your code, and enable the run-time components to work most efficiently. The purpose of each component is summarized below:

    JIT compiler. The just-in-time (JIT) compiler converts the Microsoft intermediate language (MSIL) that is contained in an assembly into native machine code at run time. Methods that are never called are not JIT-compiled.
    Garbage collector. The garbage collector is responsible for allocating, freeing, and compacting memory.
    Structured exception handling. The runtime supports structured exception handling to allow you to build robust, maintainable code. Use language constructs such as try/catch/finally to take advantage of structured exception handling.
    Threading. The .NET Framework provides a number of threading and synchronization primitives to allow you to build high performance, multithreaded code. Your choice of threading approach and synchronization mechanism impacts application concurrency; hence, it also impacts scalability and overall performance.
    Security. The .NET Framework provides code access security to ensure that code has the necessary permissions to perform specific types of operations such as accessing the file system, calling unmanaged code, accessing network resources, and accessing the registry.
    Loader. The .NET Framework loader is responsible for locating and loading assemblies.
    Metadata. Assemblies are self-describing. An assembly contains metadata that describes aspects of your program, such as the set of types that it exposes, and the members those types contain. Metadata facilitates JIT compilation and is also used to convey version and security-related information.
    Interop. The CLR can interoperate with various kinds of unmanaged code, such as Microsoft Visual Basic®, Microsoft Visual C++®, DLLs, or COM components. Interop allows your managed code to call these unmanaged components.
    Remoting. The .NET remoting infrastructure supports calls across application domains, between processes, and over various network transports.
    Debugging. The CLR exposes debugging hooks that can be used to debug or profile your assemblies.

    Performance and Scalability Issues
    This section is designed to give you a high-level overview of the major issues that can impact the performance and scalability of managed code. Subsequent sections in this chapter provide strategies, solutions, and technical recommendations to prevent or resolve these issues. There are several main issues that impact managed code performance and scalability:

    Memory misuse. If you create too many objects, fail to properly release resources, preallocate memory, or explicitly force garbage collection, you can prevent the CLR from efficiently managing memory. This can lead to increased working set size and reduced performance.
    Resource cleanup. Implementing finalizers when they are not needed, failing to suppress finalization in the Dispose method, or failing to release unmanaged resources can lead to unnecessary delays in reclaiming resources and can potentially create resource leaks.
    Improper use of threads. Creating threads on a per-request basis and not sharing threads using thread pools can cause performance and scalability bottlenecks for server applications. The .NET Framework provides a self-tuning thread pool that should be used by server-side applications.
    Abusing shared resources. Creating resources per request can lead to resource pressure, and failing to properly release shared resources can cause delays in reclaiming them. This quickly leads to scalability issues.
    Type conversions. Implicit type conversions and mixing value and reference types leads to excessive boxing and unboxing operations. This impacts performance.
    Misuse of collections. The .NET Framework class library provides an extensive set of collection types. Each collection type is designed to be used with specific storage and access requirements. Choosing the wrong type of collection for specific situations can impact performance.
    Inefficient loops. Even the slightest coding inefficiency is magnified when that code is located inside a loop. Loops that access an object’s properties are a common culprit of performance bottlenecks, particularly if the object is remote or the property getter performs significant work.

    (sursa: http://msdn.microsoft.com/en-us/library/ms998547.aspx)

    ASP.NET Performance Monitoring, and When to Alert Administrators : http://msdn.microsoft.com/en-us/library/ms972959.aspx

    Set Performance Objectives

    Your project goals must include measurable performance objectives. From the very beginning, design so that you are likely to meet those objectives. Do not over-research your design. Use the planning phase to manage project risk to the right level for your project. To accomplish this, you might ask the following questions: How fast does your application need to run? At what point does the performance of your application become unacceptable? How much CPU or memory can your application consume? Your answers to these questions are your performance objectives. They help you create a baseline for your application’s performance. These questions help you determine if the application is quick enough.

    Performance objectives are usually specified in terms of the following:
    Response time. Response time is the amount of time that it takes for a server to respond to a request.
    Throughput. Throughput is the number of requests that can be served by your application per unit time. Throughput is frequently measured as requests or logical transactions per second.
    Resource utilization. Resource utilization is the measure of how much server and network resources are consumed by your application. Resources include CPU, memory, disk I/O, and network I/O.
    Workload. Workload includes the total number of users and concurrent active users, data volumes, and transaction volumes.

    You can identify resource costs on a per-scenario basis. Scenarios might include browsing a product catalog, adding items to a shopping cart, or placing an order. You can measure resource costs for a certain user load, or you can average resource costs when you test the application by using a certain workload profile. A workload profile consists of a representative mix of clients performing various operations.

    Performance Modeling

    Performance modeling helps you evaluate your design decisions against your objectives early on,before committing time and resources. Invalid design assumptions and poor design practices may mean that your application can never achieve its performance objectives. The performance modeling process model presented in this guide is summarized in Figure.

    Eight-step performance modeling process

    Eight-step performance modeling process

    The performance modeling process consists of the following steps:
    1. Identify key scenarios. Identify those scenarios in which performance is important and the ones that pose the most risk to your performance objectives.
    2. Identify workloads. Identify how many users, and how many concurrent users, your system needs to support.
    3. Identify performance objectives. Define performance objectives for each of your key scenarios. Performance objectives reflect business requirements.
    4. Identify budget. Identify your budget or constraints. This includes the maximum execution time in which an operation must be completed and resource utilization such as CPU, memory, disk I/O, and network I/O constraints.
    5. Identify processing steps. Break your scenarios down into component processing steps.
    6. Allocate budget. Spread your budget determined in Step 4 across your processing steps determined in Step 5 to meet the performance objectives you defined in Step 3.
    7. Evaluate. Evaluate your design against objectives and budget. You may need to modify design or spread your response time and resource utilization budget differently to meet your performance objectives.
    8. Validate. Validate your model and estimates. This is an ongoing activity and includes prototyping, testing, and measuring.

    Performance Counters for ASP.NET

    ASP.NET System Performance Counters
    ASP.NET supports the ASP.NET system performance counters listed in the following table. These counters aggregate information from all ASP.NET applications on a Web server computer.

    Note:
    There is a significant difference between the State Server Sessions counters found in the ASP.NET performance object, which apply only to the server computer on which the state server is running, and the Sessions counters found in the ASP.NET Applications performance object, which apply only to user sessions that occur in-process.

    Application Restarts
    The number of times that an application has been restarted during the Web server’s lifetime. Application restarts are incremented each time an Application_OnEnd event is raised. An application restart can occur because of changes to the Web.config file, changes to assemblies stored in the application’s Bin directory, or when an application must be recompiled due to numerous changes in ASP.NET Web pages. Unexpected increases in this counter can mean that problems are causing your Web application to recycle. In such circumstances you should investigate as soon as possible.

    Note:
    This value is reset to zero every time the Internet Information Services (IIS) host is restarted.

    Application Running
    The number of applications running concurrently on the server computer.

    Requests Disconnected
    The number of requests that have been disconnected due to a communication failure.

    Requests Queued
    The number of requests waiting for service from the queue. When this number starts to increment linearly with increased client load, the Web server computer has reached the limit of concurrent requests that it can process. The default maximum for this counter is 5,000. You can change this setting in the Machine.config file.

    Requests Rejected
    The total number of requests not executed because of insufficient server resources to process them. This counter represents the number of requests that return a 503 HTTP status code, indicating that the server is too busy.

    Request Wait Time
    The number of milliseconds that the most recent request waited in the queue for processing.

    Session State Server Connections Total
    The total number of session-state connections made to the computer on which out-of-process session-state data is stored. For more information, see Session-State Modes.

    Session SQL Server Connections Total
    The total number of session-state connections made to the Microsoft SQL Server database in which session-state data is stored. For more information, see Session-State Modes.

    State Server Sessions Abandoned
    The number of user sessions that have been explicitly abandoned. These are sessions that are ended by specific user actions, such as closing the browser or navigating to another site. This counter is available only on the computer where the state server service (aspnet_state) is running.

    State Server Sessions Active
    The number of currently active user sessions. This counter is available only on the computer where the state server service (aspnet_state) is running.

    State Server Sessions Timed Out
    The number of user sessions that have become inactive through user inaction. This counter is available only on the computer where the state server service (aspnet_state) is running.

    State Server Sessions Total
    The number of sessions created during the lifetime of the process. This counter is the total value of State Server Sessions Active, State Server Sessions Abandoned, and State Server Sessions Timed Out. This counter is available only on the computer where the state server service (aspnet_state) is running.

    Worker Process Restarts
    The number of times a worker process has been restarted on the server computer. A worker process can be restarted if it fails unexpectedly or when it is intentionally recycled. If this counter increases unexpectedly, you should investigate as soon as possible.

    Worker Process Running
    The number of worker processes running on the server computer.

    ASP.NET Application Performance Counters
    ASP.NET supports the application performance counters listed in the following table. These counters enable you to monitor the performance of a single instance of an ASP.NET application. A unique instance named __Total__ is available for these counters. This instance aggregates counters for all applications on a Web server (similar to the global counters described earlier in this topic). The __Total__ instance is always available. The counters will display zero when no applications are currently executing on the server.

    Anonymous Requests
    The number of requests that are using anonymous authentication.

    Anonymous Requests/Sec
    The number of requests per second that are using anonymous authentication.

    Cache Total Entries
    The total number of entries in the cache. This counter includes both use of the cache by the ASP.NET page framework and use of the application cache through cache APIs.

    Cache Total Hits
    The total number of hits from the cache. This counter includes both use of the cache by the ASP.NET page framework and use of the application cache through cache APIs.

    Cache Total Misses
    The number of failed cache requests per application. This counter includes both use of the cache by the ASP.NET page framework and use of the application cache through cache APIs.

    Cache Total Hit Ratio
    The ratio of hits to misses for the cache. This counter includes both use of the cache by the ASP.NET page framework NET and use of the application cache through cache APIs.

    Cache Total Turnover Rate
    The number of additions and removals to the cache per second, which is useful in helping to determine how effectively the cache is being used. If the turnover rate is high, the cache is not being used efficiently.

    Cache API Entries
    The total number of entries in the application cache.

    Cache API Hits
    The total number of hits from the cache when it is accessed only through the external cache APIs. This counter does not track use of the cache by the ASP.NET page framework.

    Cache API Misses
    The total number of failed requests to the cache when accessed through the external cache APIs. This counter does not track use of the cache by the ASP.NET page framework.

    Cache API Hit Ratio
    The cache hit-to-miss ratio when accessed through the external cache APIs. This counter does not track use of the cache by the ASP.NET page framework.

    Cache API Turnover Rate
    The number of additions and removals to the cache per second when used through the external APIs (excluding use by the ASP.NET page framework). It is useful in helping determine how effectively the cache is being used. If the turnover rate is high, then the cache is not being used effectively.

    Compilations Total
    The total number of compilations that have taken place during the lifetime of the current Web server process. Compilation occurs when a file with an .aspx, .asmx, .ascx, or .ashx file name extension, or a code-behind source file, is dynamically compiled on the server.

    This number will initially climb to a peak value as requests are made to all parts of an application. Once compilation occurs, however, the resulting compiled output is saved to disk, where it is reused until its source file changes. This means that even in the event of a process restart the counter can remain at zero (inactive) until the application is modified or redeployed.

    Debugging Requests
    The number of requests that occur while debugging is enabled.

    Errors During Preprocessing
    The number of errors that occurred during parsing, excluding compilation and run-time errors.

    Errors During Compilation
    The number of errors that occur during dynamic compilation, excluding parser and run-time errors.

    Errors During Execution
    The total number of errors that occur during the execution of an HTTP request, excluding parser and compilation errors.

    Errors Unhandled During Execution
    The total number of unhandled errors that occur during the execution of HTTP requests. An unhandled error is any run-time exception that is not trapped in user code and enters the ASP.NET internal error-handling logic. Exceptions to this rule occur when:

    Custom errors are enabled, an error page is defined, or both.

    The Page_Error event is defined in user code and either the error is cleared (using the ClearError method) or a redirect is performed.

    Errors Unhandled During Execution/Sec
    The number of unhandled exceptions per second that occur during the execution of HTTP requests.

    Errors Total
    The total number of errors that occur during the execution of HTTP requests, including any parser, compilation, or run-time errors. This counter is the sum of the Errors During Compilation, Errors During Preprocessing, and Errors During Execution counters. A well-functioning Web server should not generate errors. If errors occur in your ASP.NET Web application, they may skew any throughput results because of very different code paths for error recovery. Investigate and fix any bugs in your application before performance testing.

    Errors Total/Sec
    The number of errors per second that occur during the execution of HTTP requests, including any parser, compilation, or run-time errors.

    Output Cache Entries
    The total number of entries in the output cache.

    Output Cache Hits
    The total number of requests serviced from the output cache.

    Output Cache Misses
    The number of failed output-cache requests per application.

    Output Cache Hit Ratio
    The percentage of total requests serviced from the output cache.

    Output Cache Turnover Rate
    The number of additions and removals to the output cache per second. If the turnover rate is high, the cache is not being used effectively.

    Pipeline Instance Count
    The number of active request pipeline instances for the specified ASP.NET application. Since only one execution thread can run within a pipeline instance, this number gives the maximum number of concurrent requests that are being processed for a given application. In most circumstances it is better for this number to be low when under load, which signifies that the CPU is well utilized.

    Request Bytes In Total
    The total size in bytes of all requests.

    Request Bytes Out Total
    The total size in bytes of responses sent to a client. This does not include HTTP response headers.

    Requests Executing
    The number of requests currently executing.

    Requests Failed
    The total number of failed requests. Any status codes greater than or equal to 400 will increment this counter.

    Requests that cause a 401 status code increment this counter and the Requests Not Authorized counter. Requests that cause a 404 or 414 status code increment this counter and the Requests Not Found counter. Requests that cause a 500 status code increment this counter and the Requests Timed Out counter.

    Requests Not Found
    The number of requests that failed because resources were not found (status code 404 or 414).

    Requests Not Authorized
    The number of requests that failed due to no authorization (status code 401).

    Requests Succeeded
    The number of requests that executed successfully (status code 200).

    Requests Timed Out
    The number of requests that timed out (status code 500).

    Requests Total
    The total number of requests since the service was started.

    Requests/Sec
    The number of requests executed per second. This represents the current throughput of the application. Under constant load, this number should remain within a certain range, barring other server work (such as garbage collection, cache cleanup thread, external server tools, and so on).

    Sessions Active
    The number of sessions currently active. This counter is supported only with in-memory session state.

    Sessions Abandoned
    The number of sessions that have been explicitly abandoned. This counter is supported only with in-memory session state.

    Sessions Timed Out
    The number of sessions that timed out. This counter is supported only with in-memory session state.

    Sessions Total
    The total number of sessions. This counter is supported only with in-memory session state.

    Transactions Aborted
    The number of transactions canceled for all active ASP.NET applications.

    Transactions Committed
    The number of transactions committed for all active ASP.NET applications.

    Transactions Pending
    The number of transactions in progress for all active ASP.NET applications.

    Transactions Total
    The total number of transactions for all active ASP.NET applications.

    Transactions/Sec
    The number of transactions started per second for all active ASP.NET applications.

    (sursa: http://msdn.microsoft.com/en-us/library/fxk122b4.aspx)

    10 ASP.NET Performance and Scalability Secrets

    ASP.NET 2.0 has many secrets, which when revealed can give you big performance and scalability boost. For instance, there are secret bottlenecks in Membership and Profile provider which can be solved easily to make authentication and authorization faster. Furthermore, ASP.NET HTTP pipeline can be tweaked to avoid executing unnecessary code that gets hit on each and every request. Not only that, ASP.NET Worker Process can be pushed to its limit to squeeze out every drop of performance out of it. Page fragment output caching on the browser (not on the server) can save significant amount of download time on repeated visits. On demand UI loading can give your site a fast and smooth feeling. Finally, Content Delivery Networks (CDN) and proper use of HTTP Cache headers can make your website screaming fast when implemented properly. In this article, you will learn these techniques that can give your ASP.NET application a big performance and scalability boost and prepare it to perform well under 10 times to 100 times more traffic.

    In this article we will discuss the following techniques:

    • ASP.NET pipeline optimization
    • ASP.NET process configuration optimization
    • Things you must do for ASP.NET before going live
    • Content Delivery Network
    • Caching AJAX calls on browser
    • Making best use of Browser Cache
    • On demand progressive UI loading for fast smooth experience
    • Optimize ASP.NET 2.0 Profile provider
    • How to query ASP.NET 2.0 Membership tables without bringing down the site
    • Prevent Denial of Service (DOS) attack

    The above techniques can be implemented on any ASP.NET website, especially those who use ASP.NET 2.0’s Membership and Profile provider.

    You can learn a lot more about performance and scalability improvement of ASP.NET and ASP.NET AJAX websites from my book – Building a Web 2.0 portal using ASP.NET 3.5.

    (sursa: http://www.codeproject.com/KB/aspnet/10ASPNetPerformance.aspx)

    Fast ASP.NET web page loading by downloading multiple javascripts after visible content and in batch

    Optimize ASP.NET Performance

    One of the most important things you can do to improve performance in an ASP.NET application is to reduce the number of round trips to the server. Don’t request the current page if you don’t have any processing to perform on the server before transferring the user to another page. For example, I once had a client whose most frequently used button on the most frequently used page contained a single line of code that did exactly one thing: It redirected the user to the next page. In this circumstance, you can dispense with the button and simply add a Hyperlink control to the page that causes the browser to request the next page directly. Your server will have one less page to process.

    Sometimes you use a button and a line of code because the next page needs some data from the current page. In ASP.NET 2.0, however, you can avoid requesting the current page and post the current page’s data to the server by using cross-page posting. All you have to do is set the PostBackUrl property of your button to the URL of the next page. On the new page, use the PreviousPage property to retrieve the data you need from the current page. This code retrieves the value of a control called FirstNameTextBox from the previous page:

    Dim Name As String
    Name = CType(Me.PreviousPage.FindControl( _
    “FirstNameTextBox”), TextBox).TextYou also can reduce the overhead of transferring the user from one page to another. If your user doesn’t need to bookmark a page, use the Transfer method of the Server object to send the user a new page instead of the Redirect method of the Response object. The Redirect method requires two round-trips to the server to get the user to the next page. The Transfer method simply sends the user to the new page, eliminating the overhead of a second request to the server (see Figure 1).

    Note that there is a usability cost to employing the Transfer method. You can use the Transfer method only to send the user to a page in the same site. More importantly, the browser doesn’t see the switch in pages, so the address bar of the browser reflects the URL of the original page. This can cause a complication when bookmarking the page because the user is actually bookmarking the page you transferred the user from, rather than the page the user sees. Similarly, a user refreshing the page is requesting a new version of the page specified in the address box, rather than the displayed page.

    Reduce the Server’s Load
    It’s obvious, but the less work you do on the server, the faster your server will run. Unless you take advantage of some server-side feature of a control, you should consider using the equivalent HTML control for any server-side code. For instance, do the labels on your page need to be ASP.NET server-side labels? If not, use the HTML Label control, which requires considerably less processing on the server. If all you use the DataGrid control for is to display data, you should look at switching to a Table control. You can avoid all the overhead of the DataGrid for the cost of a few lines of code to generate the rows and columns for your data. Faster yet, you can write the Table tags yourself and use a Literal control to display your HTML. It’s more work for you at design time, but less work for your server on every request for the page at run time.

    The more processing that you do on the client with client-side code, the less processing you’ll have to do on the server. ASP.NET 1.1 includes several methods for adding client-side code to your page dynamically. In ASP.NET 2.0, the tools are expanded to make it even easier to insert JavaScript into your page. Visual Studio 2005 also provides better support for client-side programming. Setting the GridView’s EnableSortingandPagingCallbacks property (or the DetailView’s EnablePagingCallbacks property) causes all sorting and paging to be performed on the client rather than on the server.

    In ASP.NET 2.0, you can use client-side code and callbacks to avoid posting the whole page back to the server for processing (see Additional Resources). A client-side callback lets you send only the data you need back to the server and then retrieve the result of your server-side processing without posting a whole page. It’s not Asynchronous JavaScript And XML (AJAX), but it works, and it reduces the overhead on your server.

    You should also consider turning off the ViewState for any control whose properties you won’t be altering from your code. Turning off the ViewState for a control reduces the data traveling between your server and the browser.

    Turning off the ViewState does come with a cost, however. It can result in your control’s client-side events firing in unexpected ways. For example, if you turn off the ViewState for a textbox, the TextChanged event fires whenever the Text property’s value is different from its default value, not every time a user changes the Text property. Avoiding code that depends on client-side events solves this problem. In ASP.NET 2.0, controls can store essential data in a section of the ViewState that is never disabled, so clever control authors can minimize unexpected side effects.

    Of course, you should consider turning off anything you don’t need. For example, ask yourself if you need authentication. ASP.NET enables authentication by default in your site’s web.config file, but you should turn it off if you’re not using it (set the authentication element’s mode attribute to None). In ASP.NET 2.0, you should also make sure you haven’t enabled personalization inadvertently. Even if you are using the ASP.NET 2.0 personalization feature, ask yourself whether you need to support personalization for anonymous users. If not, turn that off by setting the Enabled property on the anonymousIdentification element to False. The less your server does, the faster everything else will run.

    Reduce Trips to the Database
    It’s important to reduce any round trips needed by your application, not just round trips to the server. For example, you can keep data on your Web server instead of the database server by storing any data that you retrieve and might need again in the cache. And never, ever store anything bulky in the Application object—put any bulky items in the Cache object.

    Note that items in the Cache object are discarded automatically when your server starts to run out of memory. It makes sense to put as much as you can in the ASP.NET Cache object because the memory this object uses will free up automatically when (and if) it’s necessary. For example, consider that table of states and provinces that you keep retrieving from the database to display in listboxes all over your site. Instead, you might retrieve that table into a DataSet stored in the Cache object and bind all your listboxes to that table in the DataSet. Yes, the DataSet takes up memory, but the cache discards the DataSet if memory runs short.

    If you use this approach, you must add code to check whether the DataSet is still present in the Cache object before you use the DataSet. But the worst that can happen is that you must go back to the database for your data. You’re no worse off than before, and you’ve probably saved yourself dozens of trips to the server when memory was available. If you need some information to know which item to retrieve from the database when the Cache object dumps your object (a customer number, for instance), store that small amount of data in the Application or Session objects.

    Using the Cache object this way gives you an in-memory data store that adapts automatically to changing conditions. The items you haven’t used for the longest period of time are removed from the Cache object first, so you’re guaranteed that your most frequently used objects will stick around the longest. Your code only adds back to the cache the items your program uses, so only the objects that you need creep back into memory. This approach is extremely efficient.

    Exploiting the cache is even easier in ASP.NET 2.0 if you use the SqlDataSource object. You can turn on caching for your data by setting the EnableCaching property on the SqlDataSource to True. In this case, you need to ensure that the data you cache doesn’t get out of date relative to the data in the database. Fortunately, there’s an easy fix for this: Simply make sure the SqlDataSource discards cached data after a specified time by setting the DataSource’s CacheDuration property to the number of seconds to hang onto the data.

    You should also consider using the OutputCache object for your pages. For example, consider whether you need to regenerate all your pages each time you request them. If not, adding an OutputCache to your page in source view allows you to generate your page once for the first user who requests it and then display that same page for every subsequent user. Assuming you create only a handful of versions of the page, and assuming that you control these versions in the data sent to the page, you can use the VaryByParam attribute to cache those different versions. This directive ensures that you keep copies of the page for 10 minutes for each of the different values of the CustomerText and CountryText controls:

    ASP.NET 2.0 includes its own new wrinkles. Assume you have a page that contains a small part that you must regenerate for each request. You can use a Substitution control to define that part of the page. Simply set the control’s MethodName property to the name of the function that provides the content for the control, and ASP.NET caches the rest of your page’s HTML. This means your server has to generate much less HTML, improving server performance.

    This might seem like a natural place to discuss ASP.NET 2.0’s ability to discard cached data automatically if the data in the database changes. However, it remains unclear whether this feature will improve your performance if you don’t also use SQL Server 2005. With the current versions of SQL Server, enabling dependencies between SQL Server and ASP.NET requires ASP.NET to check back with SQL Server on some schedule to see if data has changed. This extra work could degrade your performance more than caching helps it.

    Caching also demonstrates what I said at the start of the article: Performance is often a trade-off between speed and memory. Faster processing often comes at the cost of using more memory or at the cost of changing your application’s behavior.

    The SqlDataSource object’s DataSourceMode in ASP.NET 2.0 provides another demonstration of this rule. Setting the SqlDataSource’s DataSourceMode to DataReader gives you the least memory consumption and fastest processing when retrieving data. However, controls bound to a SqlDataSource can lose some functionality when DataSourceMode is set to DataReader (the DataGrid won’t be able to sort or filter data). Setting DataSourceMode to DataSet gives you that functionality, but at the cost of having the SQLDataSource take up more room in memory and take a little longer to retrieve your data. You might have to experiment to find what gives your site the best results.

    Watch for Errors and COM
    Things can go wrong, and you should provide error handling to catch those problems. But don’t use error handling to take care of conditions that you can check for (unless those conditions are extremely rare). Exception handling is expensive in ASP.NET. You get better performance by checking for a condition and not raising the error than you do by putting the code in a Try block and hoping the condition doesn’t exist. In other words, check whether your divisor is not equal to zero before dividing—don’t attempt the division in a Try block.

    If your application started life as an ASP page with VBScript, then you implemented your error handling using On Error Resume statements. ASP.NET supports using On Error Resume for Visual Basic—but it’s extremely slow. Replace your On Error Resume statements with Try blocks.

    If you call a COM object from your ASP.NET page, you need to do more than set your variables to nothing to release your COM objects. Setting a variable to nothing only makes the wrapper that .NET puts around your COM object available for garbage collection. It can be a long time before your wrapper gets garbage collected, and your COM object hangs around in memory until that happens. Use the ReleaseComObject method of the System.Runtime.InteropServices.Marshal object when you finish with an object, passing the reference to your COM object to release it. Your .NET wrapper still must wait for the garbage collector to collect it before you can get back the memory held by your COM object.

    Unfortunately, there is a catch when using ReleaseComObject: Under some circumstances, you must call the method more than once. In fact, you must keep calling ReleaseComObject until the method returns 0 to ensure that your COM object is released. This code does the trick:

    Dim ComObject As SomeCOMObject
    Do Until System.Runtime.InteropServices. _
    Marshal.ReleaseComObject(ComObject) = 0
    LoopASP.NET 2.0 provides a simpler solution: Call the Marshal object’s FinalReleaseComObject method, passing your object like this:

    System.Runtime.InteropServices.Marshal. _
    FinalReleaseComObject(ComObject)Another important performance principle is to make sure that you get the fastest (and fewest) compiles. In ASP.NET 1.0, you should change your application’s Configuration setting before you release it. Simply select Build | Configuration Manager and change your application’s Configuration setting to Release. This gives you a more optimized build and skips generating any debug support.

    Note that your application’s code is never fully compiled when it leaves Visual Studio—at best, .NET converts your code to IL code, but the code must be compiled to native code after you install the application on the server. In ASP.NET 1.1, this final compilation happens the first time that a page is requested from the site. You shouldn’t make your users wait for your site to compile; instead, you should force compilation by requesting a page from the site yourself.

    The situation is compounded in ASP.NET 2.0 where two of the deployment methods (copying the Web site and creating a setup package) don’t even compile your source code to IL. Only Build | Publish Web Site generates IL code. You can force compilation for your Web site by calling the precompile.axd utility after installing your application (the utility ships with .NET 2.0). All you need to do is append the utility’s name to the end of your site’s URL, like this: http://MyServer/MySite/precompile.axd. 

    (sursa: http://visualstudiomagazine.com/columns/article.aspx?editorialsid=1987)

    Speed Optimization in ASP.NET 2.0 Web Applications – Part 2

    Page and Server Controls
    The following topics give you an idea about how to use pages and controls efficiently in your web application:

    Use HTML controls whenever possible
    HTML controls is lighter than server controls especially if you are using server controls with its default properties. Server controls generally is easier to use than HTML controls, and on the other side they are slower than HTML controls. So, it is recommended to use HTML controls whenever possible and avoid using unnecessary server controls.

    Avoid round trips to server whenever possible
    Using server controls will extensively increase round trips to the server via their post back events which wastes a lot of time. You typically need to avoid these unnecessary round trips or post back events as possible. For example, validating user inputs can always (or at least in most cases) take place in the client side. There is no need to send these inputs to the server to check their validity. In general you should avoid code that causes a round trip to the server.

    The Page.IsPostBack Property
    The Page.IspostBack Boolean property indicates whether this page is loaded as a response to a round trip to the server, or it is being loaded for the first time. This property helps you to write the code needed for the first time the page is loaded, and avoiding running this same code each time the page is posted back. You can use this property efficiently in the page_load event. This event is executed each time a page is loaded, so you can use this property conditionally to avoid unnecessary re-running of certain code.

    Server Control’s AutoPostBack Property
    Always set this property to false except when you really need to turn it on. This property automatically post back to the server after some action takes place depending on the type of the control. For example, in the Text Control this property automatically post back to the server after the text is modified which is a great deal of processing cost and hence much slower performance and most importantly a poor user experience.

    Leave Buffering on
    It is important to leave page buffering in its on state to improve your page speed, unless you have a serious reason to turn it off.

    Server Controls View State
    Server control by default saves all the values of its properties between round trips, and this increases both page size and processing time which is of course an undesired behavior. Disable the server control view state whenever possible. For example, if you bind data to a server control each time the page is posted back, then it is useful to disable the control’s view state property. This reduces page size and processing time.

    Methods for redirection
    There are many ways you can use to redirect a user from the current page to another one in the same application, however the most efficient methods to do this are: the Server.Transfer method or cross-page posting.

    Web Applications
    The following topics give you some tips about how to make an efficient web application:

    Precompilation
    When an already deployed ASP.NET web application page is requested for the first time, that page needs to be compiled (by the server) before the user gets a response. The compiled page or code is then cached so that we need not to compile it again for the coming requests. It is clear that the first user gets a slow response than the following users. This scenario is repeated for each web page and code file within your web site.
    When using precompilation then the ASP.NET entire web application pages and code files will be compiled ahead. So, when a user requests a page from this web application he will get it in a reasonable response time whatever he is the first user or not.
    Precompiling the entire web application before making it available to users provides faster response times. This is very useful on frequently updated large web applications.

    Encoding
    By default ASP.NET applications use UTF-8 encoding. If your application is using ASCII codes only, it is preferred to set your encoding to ASCII to improve your application performance.

    Authentication
    It is recommended to turn authentication off when you do not need it. The authentication mode for ASP.NET applications is windows mode. In many cases it is preferred to turn off the authentication in the ‘machin.config’ file located on your server and to enable it only for applications that really need it.

    Debug Mode
    Before deploying your web application you have to disable the debug mode. This makes your deployed application faster than before. You can disable or enable debug mode form within your application’s ‘web.config’ file under the ’system.web’ section as a property to the ‘compilation’ item. You can set it to ‘true’ or ‘false’.

    Coding Practices
    The following topics give you guidelines to write efficient code:

    Page Size
    Web page with a large size consumes more bandwidth over the network during its transfer. Page size is affected by the numbers and types of controls it contains, and the number of images and data used to render the page. The larger the slower, this is the rule. Try to make your web pages small and as light as possible. This will improve response time.

    Exception Handling
    It is better for your application in terms of performance to detect in your code conditions that may cause exceptions instead of relying on catching exceptions and handling them. You should avoid common exceptions like null reference, dividing by zero , and so on by checking them manually in your code.

    Garbage Collector
    ASP.NET provides automatic garbage collection and memory management. The garbage collector’s main task is to allocate and release memory for your application. There are some tips you can take care of when you writing your application’s code to make the garbage collector works for your benefit:

    Avoid using objects with a Finalize sub as possible and avoid freeing resources in Finalize functions.
    Avoid allocating too much memory per web page because the garbage collector will have to do more work for each request and this increases CPU utilization (not to mention you can go out of memories in larger web applications)
    Avoid having unnecessary pointers to objects because this makes these objects alive until you free them yourself within your code not in an automatic way.

    Use Try / Finally
    If you are to use exceptions anyway, then always use a try / finally block to handle your exceptions. In the finally section you can close your resources if an exception occurred or not. If an exception occurs, then the finally section will clean up your resources and frees them up.

    String Concatenation
    Many string concatenations are time consuming operations. So, if you want to concatenate many strings such as to dynamically build some HTML or XML strings then use the System.Text.StringBuilder object instead of system.string data type. The append method of the StringBuilder class is more efficient than concatenation.

    Threading
    If your application contains some operation that consumes time and resources, then instead of blocking the application flow awaiting for this process or operation to be finished it is recommended to create a separate thread for this blocking operation. By threading you will save your application normal flow from delays. Examples of time consuming operations that can be moved to another thread other than the main program thread are: querying on a database and waiting for results, and extensive IO operations.

    (sursa: http://www.beansoftware.com/asp.net-tutorials/controls-coding-optimization.aspx)