High-Performance .NET Application Development & Architecture

General .NET Best Practices

The best practices to be discussed stem from real-world .NET application use, and have proven themselves very viable and sound in producing very scalable, high-performance applications. Since I'll be dealing with .NET programming a la hand coding and web forms, those interested in strict Visual Basic.NET optimizations should see - Performance Optimization in Visual Basic .NET for more info. Nevertheless, the best practices discussed here, generally apply to VB.NET as well. Moreover, all the tips offered here are general application page optimizations.

  • Right at the top of your .aspx page's @ Page directive, it is always important to disable any features you won't need or use. For example, set EnableSessionState to false on any pages not requiring use of session state, as well as Debug, Trace and EnableViewState. Alternatively, if you need to access Session State values but won't be modifying any, then use EnableSessionState="ReadOnly". For strongly-typed error-free compilation, Strict and Explicit should be set to true to enforce early binding and variable declaration. Moreover, always set the page's Buffer to true for nice performance boosts, and application-wide within the web.config file's system.web nodes as well - <pages buffer="true"/> .
    <%@ Page Language="C#" Debug="false" Strict="true" Explicit="true"
    Trace="false" EnableSessionState="false" EnableViewState="false"
    Buffer="true" %>
    Note, all of the above attributes are applicable to an .ascx user-control's @ Control directive, except for Buffer, Trace and EnableSessionState.


  • Another important attribute of the @Page directive is AutoEventWireup. When this attribute is set to true, the .NET runtime doesn't require events on the page like Page_Load or Page_Init to indicate any implicit event handlers like the Handles clause, rather it takes care of them for you. You probably may have changed this attribute in the past only to discover that your controls wouldn't fire, well this is why. Therefore, to improve performance and handle events manually, set AutoEventWireup="False" and override the method. So, our commonplace Page_Load as shown,
    void Page_Load (Object sender, EventArgs e) {
    
    //Your code here
    
    }
    
    is transformed to the overridden method event shown below. In order to override the default event handler, you'll need to rename Page_Load to OnLoad and change its access modifier keyword to Protected. Also notice how its Sender parameter is omitted, so that it matches the event handler.
    [C#]
    
    protected override void OnLoad (EventArgs e) {
    
    //Your code here
    
    }
    
    [VB]
    
    Protected Overrides Sub OnLoad (e As EventArgs)
    
    'Your code here
    
    End Sub
     
         
  • On Page_Load set Response.BufferOutput to true and Response.Flush at some later key point in your code.
    void Page_Load(Object sender, EventArgs e) { 
    
        Response.BufferOutput = true; 
    
        //...... 
    
        Response.Flush(); 
    
    } 
  • Utilize Page caching by incorporating the @ OutputCache directive to speed up page display by storing this page is memory. You start by specifying, in seconds, the duration for the cache to remain in memory, your particular request scenario and its location. Other customizable request attribute settings include VaryByCustom, VaryByHeader, VaryByParam and VaryByControl , and for the Location attribute (not supported in User Controls or .ascx files) you're allowed - "Any | Client | Downstream | Server | None."
    <%@ OutputCache Duration="7200" VaryByParam="value" Location="Any" Shared="True" %>
    Output caching could also be enabled with the HttpCachePolicy Class. Not only that, but the OutputCache directive include-syntax also fully applies to Fragment Caching or caching server user controls (.ascx) files separately as well, and works along the exact same lines. However, one distinct advantage this has over standard Page output caching, is that the user control file supports the Shared attribute setting, whereas the .NET Web Forms page (.aspx) does not.

    Therefore, by setting your server user control's Shared attribute to true, you in effect allow this control to be shared among all your pages, as opposed to creating separate cached versions of it. As you can probably guess, you'll end up with more available memory and even better performance!

    Now that's not all, caching your code-behind's source file is very different from what we've seen. To cache your code-behind control you'd declaratively implement the duration attribute in your source file's metadata like so:

    [C#]
    [PartialCaching(7200)] 
    
    public class myClass : UserControl { 
    
       //Your code here 
    
    }

    [VB]
    <PartialCaching(7200)> _ 
    
    Public myClass : Inherits UserControl 
    
       'Your code here 
    
    End Class
    Reference PartialCachingAttribute Classfor more info.
  • Aside from Page Caching, Data Caching is extremely important, and what you tend to do once you present data to the client. How have you developed the page in question in light of scalabilty and performance? If the user is returned 10,000 records that will assuredly require paging, will your application keep re-hitting the database each time or does it take advantage of .NET's data caching methods?

    I have written two articles that cover such topics in much greater detail .NET Data Caching and Drilldown Datagrid Searching with ASP.NET. I'll refer you to these two articles for all the information you'll need. As for more generalized data access, we'll be discussing this in greater detail in our Data Layer section, and reveal different scenarios and the best data retrieval method to be used for the best performance.

  • Check for Postback on Page_Load to avoid unnecessarily hitting the server when the page is posting back to itself:
    void Page_Load(Object sender, EventArgs e) { 
    
       if ( !IsPostBack ) { 
    
         //...rest of code here 
    
       } 
    
    }
  • Use Server.Transfer instead of Response.Redirect to redirect any virtual pages on the server, as doing so avoids checking for postback before it executes, thereby conserving server resources. Note, that this method won't work of course when redirecting to an external site.

    Additionally, if your page contains form variables that also need to get transferred, just set Server.Transfer's preserveForm boolean parameter to "True", like so: Server.Transfer("MyPage.aspx", True)
  • Don't unnecessarily use server-side web server controls for simple tasks where standard HTML controls would suffice.
  • Use .NET's StringBuilder class for all your string writing/creation and manipulation needs.
  • When it comes to your code and values try to minimize boxing and unboxing of values, as this can cause a performance hit.
  • Be very paranoid when it comes to any text you'll be accepting through forms, or query strings. Unless imperative and not practical although easier, utilize POST primarily instead of GET, for any data requests or passing among pages.
  • Use <%@ Page AspCompat="true" %> only if it's an absolute must where you require pre-.NET apartment-threaded VB6 COM object compatibility. It truth, it's best that you simply make the effort to fully migrate your application completely to .NET, as this is better in the long run.
  • Particular settings within your configuration file - web.config , prove useful in improving application performance. First of all, set all pages to buffer, as mentioned. Second, if your site is fully public, setting authentication to None mode further helps, as well as disabling site wide debugging. No public pages or applications should ever have debug mode enabled.
    <system.web>
       <authentication mode="None" /> 
       <pages buffer="true" /> 
    <trace enabled="false" /> <compilation debug="false" /> </system.web>
  • Take advantage of .NET's machine.config file processModel attributes. They have much to do with the robustness of the application as it's the server and how well it lives that will further epitomize your application. The old days of rebooting IIS for component registration or recycling and so forth are long gone with all of .NET's way cool abilities contained within this one file. Heck, this file even helps with automatic crash recovery! Read Configuring the ASP.NET Worker Process through the <machine.config> file for some good tips.
  • When compiling any classes in a code behind scheme or as a data object, outside of VS.NET, use /optimize thus assuring smaller, more efficient runtime code:
    (csc/vbc).exe /t:library /out:c:\inetpub\wwwroot\bin\sf.dll sf.(cs/vb) /optimize

Within VS.NET, you could enable optimizations through your Project Solutions properties, under Configuration Properties-->Optimizations.

Furthermore, you could utilize .NET's Native Image Generator (Ngen.exe) to cache your components or applications (.exe) within the GAC (Global Assembly Cache) for faster start-up times:

ngen myComponent.dll/exe
  • When possible and applicable, utilize Asynchronous Calls for added scalability to your application, anywhere from I/O actions to ASP.NET Web Forms.
  • Always, always remember to close, null and dispose of all your objects. Even though .NET's garbage collection scheme is magnificent, do it as well nevertheless.
  • For maximum readability, always properly indent your code.
  • And finally, add comments to your code. .NET comment tags are <%-- Code --%> , whereas dependent on the language you've chosen, VB uses an apostrophe ' to comment out code and C# uses slashes // . This practice ensures not forgetting certain logic or program flow when the time arises. We don't always remember why we coded what we did or how, do we?

Now that we've gotten some great performance enhancing tips for our standard .NET pages, we'll proceed to the N-Tier portions, and individually deal with each one.

You might also like...

Comments

About the author

Dimitrios Markatos

Dimitrios Markatos United States

Dimitrios, or Jimmy as his friends call him, is a .NET developer/architect who specializes in Microsoft Technologies for creating high-performance and scalable data-driven enterprise Web and des...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“To iterate is human, to recurse divine” - L. Peter Deutsch