ASP.NET

Using the Data Cache

Using the data cache in the simplest and most nave way supported by ASP.NET is very like accessing the Session object. Remember, accessing the Session object involves using an indexer (the square brace syntax) and a consistent index to store and retrieve data. The data cache works in exactly the same way (although it has some other features for managing items in the cache).

The strategy for caching a piece of data usually involves these steps:

  1. Look in the cache for the data element.

  2. If it's there, use it (bypassing the expensive database round-trip).

  3. If the data is unavailable in the cache, make a round-trip to the database to fetch it.

  4. Cache the data so it's available next time around.

The next example modifies the UseDataList page so that it stores the data in the cache after acquiring it for the first time. While the first time Page_Load is called, subsequent calls are infinitely faster.

Using the Cache

  1. Open the UseDataList.aspx.cs file and go to the GetInventory method.

  2. Modifying the method to use the cache is fairly straightforward. The following listing highlights the changes. First, check to see if the item is in the cache. If searching the cache for the DataSet turns up a valid pointer, then you may bypass the database lookup code and return the DataSet. If searching the cache turns up a null pointer, go ahead and make the round-trip to the database. When the database lookup finishes, you'll have a good DataSet. Cache it before returning the reference to the caller. If you include the Trace statements, you'll be able to see exactly how big an impact caching can make.

    protected DataTable GetInventory()
    {
       DataTable dt;
    
    Trace.Warn("Page_Load", "looking in cache");
    C:dt = (DataTable)Cache["InventoryDataTable"];
    Trace.Warn("Page_Load", "done looking in cache");
    
      if (dt == null)
      {
    
          Trace.Warn("Page_Load", "Performing DB lookup");
    
            dt = new DataTable();
    
            String strConnection =
            @"Provider=Microsoft.Jet.OLEDB.4.0;
            DataSource=c:
        \\inetpub\\wwwroot\\SessionState\\App_Data\\ASPDotNetStepByStep.mdb";
    
           DbProviderFactory f =
           DbProviderFactories.GetFactory("System.Data.OleDb");
    
           DbConnection connection = f.CreateConnection();
           connection.ConnectionString = strConnection;
    
           connection.Open();
           DbCommand command = f.CreateCommand();
           command.CommandText = "Select * from DotNetReferences";
           command.Connection = connection;
    
           IDataReader reader = command.ExecuteReader();
    
           dt.Load(reader);
    
           reader.Close();
           connection.Close();
           connection.Dispose();
    
         Cache["InventoryDataTable"] = dt;
         Trace.Warn("Page_Load", "Done performing DB lookup");
    
       }
       return dt;
    }
    

    This code reduces the cost of loading the page significantly (after the data is loaded in the cache, of course). Next time the page is loaded, it'll use the cached version-available through Cache at a tremendously reduced cost. How much is the cost savings? It's huge-as you can see looking at the trace pages for the application. Let's take a peek.

Impact of Caching

If you included the Trace statements in the GetInventory method, then you can surf to the trace page to see the effect of caching. The UseDataCaching application included here has the Trace attribute turned off in the page, but has application tracing turned on. That is, the Web.Config includes the following section:

<configuration>
   <system.web>
   <trace enabled="true" />
   <system.web>
</configuration>

You can see the trace information by surfing to the virtual directory with a file name of Trace.axd. Here's the URI for following the trace information:

http://localhost/UseDataCaching/trace.axd

Figure 14-1 shows the trace statements produced by accessing the page for the first time. The column furthest to the right indicates the time elapsed since the previous trace statement. The trace statement shows that 0.558656 seconds passed while the page was loading the DataSet. That's over a half-second.

Figure 14-1 Hitting the database takes over a half second in this scenario.
Figure 14-1 Hitting the database takes over a half second in this scenario.

Make a few more posts to the page (for example, add some items from the inventory to the selected items grid). Then go back and look at the tracing information for the subsequent post-backs. Figure 14-2 shows some example trace statements. Fetching from the Cache is dramatically faster than hitting the database-by several orders of magnitude! Again, you may not notice the difference with just one client surfing the page every once in a while. However, when multiple clients are surfing to the same page simultaneously, they'll get their responses much more quickly than if the page had to make a round-trip to the database.

Figure 14-2 Fetching data from the cache takes 0.000039 seconds.
Figure 14-2 Fetching data from the cache takes 0.000039 seconds.