Caching Dynamic Pages with ASP.NET

Share this article

Interested in .NET? Don’t miss SitePoint’s .NET Feature Guide — it’s an excellent resource!

Caching is the method of saving data to some form of memory (generally computer, not yours) with the aim of speeding up the time it takes to access that data. When you access a page, your browser will cache the page on your computer so that if you pressed the back button, it wouldn’t have to download the page files again.

This isn’t a new concept — CPU manufacturers have been doing it for years — but caching dynamic Web pages has historically been a difficult and unmanageable task for developers. Many people accomplished caching using the Application State in ASP, or using third party software.

Why do you want to cache?

The attraction of caching is that it can increase performance of an application. Imagine a page that made a request to a database 30,000 times a day. With caching you could cut that down to 1 request a day, even once a week!

That’s the attraction of caching!

ASP.NET offers many different ways to cache information, and control when it happens and what is cached. Using HTTP 1.1 capable mechanisms, ASP.NET can cache pages in the browser (on the client’s computer really), proxy servers and the Web server on which the application resides. You can cache entire pages, sections of pages, and even objects you created in your code (DataSets, Web Services)! And all it takes is one line of code! This is possibly one of my favourite features of ASP.NET!

Due to the sheer size of ASP.NET’s caching abilities, I’m only going to cover caching pages here.

Prerequisites

I’ll assume that you have a basic knowledge of ASP.NET development, including a grasp on working with data, form authentication and working with SQL Server or MSDE.

Getting Started

As I said in the introduction, just about all caching can be done with one line of code, and that line is:

<%@ OutputCache Duration="60" VaryByParam="None" %>

The two properties defined in the tag are the only properties required. The Duration property defines, in seconds, how long the page is to be cached and the other, VaryByParam, defines a query string (both POST and GET) key that would automatically remove the page from the cache.

And that’s it! The page is cached. Though the line above is the most basic way to cache pages, but even this alone can start introducing better performance to your site.

The OutputCache directive has 3 other properties that can control the caching of the page:

  • Location
  • VaryByCustom
  • VaryByHeader

Each offers a different way to control the cached page, which means that caching in ASP.NET is very flexible!

Now, let’s go over each property in more detail.

Duration

As I already said, this controls how long the page is cached, provided it isn’t removed by something else. This property is defined in seconds, and is required. If Duration‘s left out, it will return a parse error (bad).

Location

This property defines where the page is to be cached. There are 5 options, all of which can be found in the OutPutCacheLocation enumeration, which is part of the System.Web.UI namespace.

  1. Any
    This is the default value. It basically will try to cache it wherever it can (and by that I mean in one of the locations listed below, not in your cupboard!).

  • Client
    This option caches the page in the client’s browser.
  • Downstream
    This caches the page in any HTTP 1.1 enabled device other than the original server. Usually includes a proxy server or the client.
  • Server
    Caches the page in the server memory.
  • None
    Disables output caching for the requested page, the same as leaving the tag out.
  • VaryByParam

    This property lets you define what parameters, either sent through POST or GET, will remove the page from the cache. This will overwrite the Duration property and remove the page from the cache. More than one value can be defined by separating each with a comma, and a wildcard (*) can be used to account for every variation. So an example of the tag with one parameter is:

    <%@ OutputCache Duration="30" VaryByParam="username" %> 
    <html>
      <body>
         Page was cache at: <strong><%=dateTime.Now.toString("G")%></strong>
      </body>
    </html>

    Every time a different username is sent, the page will be removed from the cache. Try going to the page with no query string, taking note of the time. Now add ?username=bob at the end of the URL and the time will change. Remove the query string and return to the page, it will say the same time as it did the first time. And if you wait 30 seconds and refresh the page, the time will be different!

    VaryByCustom

    To make the Cache object even more flexible, Microsoft built in the ability to cache the page based on a string, which is then controlled from the actual code of the application.

    It does have one “out of the box” property, Browser. When VaryByCustom is set to Browser the page is cached every time a different browser agent and major version number requests the page.

    So if you had a page with this at the top of it:

    <%@ OutputCache Duration="60" VaryByCustom="Browser" VaryByParam="none" %> 
    <html>
      <body>
         Page was cache at: <strong><%=dateTime.Now.toString("G")%></strong>
      </body>
    </html>

    the time would only change when a different browser visited the page, or 60 seconds had passed.

    You can also use a custom key and value by overriding the HTTPApplication.GetVaryByCustom method in the Global.asax file.

    Ok. It’s time for the part where we have to think…

    Let’s say you wanted to cache a page that passed on who was logged into your site. Let’s start by looking at the page we want to cache.

    <%@ Page Language="VB" Debug="true" %>  
    <%@ OutputCache Duration="300" Location="Server"  
    VaryByCustom="userLogged" VaryByParam="None" %>  
    <%@ import Namespace="System.Data" %>  
    <%@ import Namespace="System.Data.SQLClient" %>  
    <script runat="server">  
     
    Dim pageTimeDate As DateTime  
     
    Sub Page_Load(byVal obj As Object, byVal e As EventArgs)  
      userName.Text = Context.User.Identity.Name  
    End Sub  
     
    Sub logOut(ByVal obj As Object, ByVal e As EventArgs)  
      FormsAuthentication.SignOut()  
    End Sub  
     
    </script>  
    <html>  
      <head>  
      </head>  
      <body>  
      <form runat="server">  
         Page cached: <%=DateTime.Now.toString("G")%>  
         <br />  
         Logged in as:  
         <asp:Label id="userName" runat="server">Label</asp:Label>  
         <br />  
         <asp:Button id="Button1" onclick="logOut" runat="server"  
    Text="Log Out"></asp:Button>  
    </form>  
    </body>  
    </html>

    On the first line, we set the OutputCache directive’s VaryByCustom to userLogged. Using the Page_Load sub-routine, we display the current logged in user (using a label called username) and display the time. We also have a logout button, so we can easily log in as someone else to test the script.

    Now we’ll look at the script to set the userLogged string.

    As I said earlier, we have to override the HTTPApplication.GetVaryByCutom attribute, and we can do this in the global.asax file. Anyone that has worked with ASP extensively will be familiar with the global.asa file. This file, which resides in the root of your site, allows you to handle application level functions that need to be fired every time the application’s started, or a new session is created.

    With ASP.NET, the global.asa file has been kept, but renamed to global.asax (and is known as the ASP.NET application file), but it essentially does the same thing. This file is completely optional, and you can find out more about it at the MSDN site.

    Now, let’s move on with our code…

    At the start of the file (the global.asax file), just after the <script> tag, add the following:

    Public Overrides Function GetVaryByCustomString(ByVal   
    currentContext As HTTPContext, ByVal customArgs As String)  
    As String  
      Select CustomArgs  
         Case "userLogged"  
            Return "userLogged=" & Context.User.Identity.Name  
         Case Else  
            Return MyBase.GetVaryByCustomString(currentContext, customArgs)  
      End Select  
    End Function

    Firstly we override (hence the Overrides keyword) the GetVaryCustomString method. It has two parameters, the first being the HTTPContext (this contains all HTTP specific information about the page request), while the other is a string that represents the value of the VaryByCustom attribute. As our VaryByCustom attribute is userLogged, it will be passed to our function as a parameter when the page is requested. We use a Select statement to check what the customtArgs parameter is, and because of this, we can easily add other values, meaning that we can cache pages in a number of different ways.

    If the string has been cached, this is considered a “hit” and the page is served from the cache. If the string hasn’t been cached, then this is considered — you guessed it — a “miss”, and is cached.

    And that’s all there is to it.

    VaryByHeader

    Every time you request a Web page, your browser sends a number of HTTP headers. You can customise caching according to what these headers are, so, for instance, you can cache pages on things like the Referer, or Accept-Language. You can find a list of HTTP Headers here. You’d use it like so:

    <%@ OutputCache Duration="30" VaryByParam="none" VaryByHeader="Referer" %>

    As with most of the information we’ve gone over so far, this is a simple attribute defined in the OutputCache tag! This simple example will cache pages for 30 seconds based on the Referer.

    Finishing Up

    As we’ve just seen, caching Web pages with ASP.NET is amazingly easy, accomplished with a simple line. With this glimpse of ASP.NET’s caching abilities, you can improve your Web application’s performance. But remember: what we covered in this article is only a small part of the whole caching namespace! Try some of the other objects, experiment away, and in no time at all your applications be working faster, more efficiently, and have a lighter server load!

    This article is part of SitePoint’s .NET Feature Guide — an excellent resource for aspiring and experienced .NET developers. Don’t miss it!

    Frequently Asked Questions (FAQs) about Dynamic Pages in ASP.NET

    What is the difference between static and dynamic content in ASP.NET?

    Static content refers to files that are served directly to the user without any modification, such as HTML files, images, and stylesheets. On the other hand, dynamic content is generated in real-time based on user interaction or specific conditions. In ASP.NET, dynamic content is typically created using server-side scripting languages like C# or VB.NET. The server processes these scripts to generate HTML that is sent to the client’s browser.

    How can I create dynamic pages in ASP.NET?

    Creating dynamic pages in ASP.NET involves using server-side scripting to generate HTML content. This is typically done using Razor syntax, which allows you to embed server-based code into your HTML. The server processes this code to generate the final HTML that is sent to the client’s browser. You can create dynamic pages in ASP.NET by adding Razor Pages to your project, which are essentially .cshtml files that contain both HTML and C# code.

    What is Razor syntax in ASP.NET and how is it used?

    Razor syntax is a server-side markup language used in ASP.NET to create dynamic web pages. It allows you to embed C# or VB.NET code directly into your HTML. The server processes this code to generate the final HTML that is sent to the client’s browser. Razor syntax is clean, lightweight, and easy to understand, making it a popular choice for creating dynamic web content in ASP.NET.

    How can I use input values from the same page in ASP.NET Razor Pages?

    In ASP.NET Razor Pages, you can use the @Model directive to access data from the same page. This data can be input values from form fields, data retrieved from a database, or any other data that is part of your page model. You can then use this data in your Razor syntax to generate dynamic content based on the user’s input.

    What is the role of master pages in ASP.NET?

    Master pages in ASP.NET provide a consistent layout for multiple pages in your web application. They define a common structure that is shared across multiple pages, such as headers, footers, and navigation menus. This allows you to maintain a consistent look and feel across your website, while still allowing individual pages to have their own unique content.

    How can I cache dynamic content in ASP.NET?

    Caching dynamic content in ASP.NET can be achieved using the Output Caching feature. This allows you to store the generated HTML of a page or a portion of a page in memory, reducing the load on your server and improving performance. You can control how long the content is cached for, and under what conditions it should be regenerated.

    What is scaffolding in ASP.NET Razor Pages?

    Scaffolding in ASP.NET Razor Pages is a code generation framework that allows you to quickly create pages for basic CRUD (Create, Read, Update, Delete) operations. It can generate code for interacting with a database, including code for retrieving data, inserting new data, updating existing data, and deleting data. This can significantly speed up the development process, especially for simple data-driven websites.

    How can I handle errors in ASP.NET Razor Pages?

    Error handling in ASP.NET Razor Pages can be done using try-catch blocks, which allow you to catch exceptions that occur during the execution of your code. You can then handle these exceptions in a way that is appropriate for your application, such as displaying an error message to the user, logging the error for debugging purposes, or redirecting the user to an error page.

    How can I secure my ASP.NET Razor Pages?

    Security in ASP.NET Razor Pages can be achieved through a combination of techniques. This includes using secure communication protocols like HTTPS, validating and sanitizing user input to prevent attacks like SQL injection and cross-site scripting, and implementing authentication and authorization to control access to your pages. ASP.NET also provides built-in features for handling security, such as the AntiForgeryToken attribute for preventing cross-site request forgery attacks.

    How can I optimize the performance of my ASP.NET Razor Pages?

    Performance optimization in ASP.NET Razor Pages can be achieved through a variety of techniques. This includes caching dynamic content to reduce server load, optimizing your database queries to reduce latency, and minifying your HTML, CSS, and JavaScript files to reduce their size and improve load times. You can also use tools like the Performance Profiler in Visual Studio to identify and fix performance bottlenecks in your code.

    Chris CanalChris Canal
    View Author

    Chris works as a Web Developer for a Scottish based web design firm, and is a partner at NMC Group, Inc.. His pride and joy, apart from his fiancee, is his e4ums site, which offers free ASP applications.

    Share this article
    Read Next
    Get the freshest news and resources for developers, designers and digital creators in your inbox each week