Wednesday, 14 December 2011

Caching objects

While the OutputCache directive is easy to use and work with, it allows you only to cache the entire page, or an entire UserControl. While this is just fine for some situations, there will be times where caching an object will be much smarter. While the following example might seem a bit silly, it does show how the Cache object can be used to store for instance an ArrayList with custom objects in it. Create a new project, or use an existing page and change the CodeBehind Page_Load method to something like this (this example doesn't require you to modify the markup part):
protected void Page_Load(object sender, EventArgs e)
{
    ArrayList datestamps;
    if(Cache["datestamps"] == null)
    {
        datestamps = new ArrayList();
        datestamps.Add(DateTime.Now);
        datestamps.Add(DateTime.Now);
        datestamps.Add(DateTime.Now);

        Cache.Add("datestamps", datestamps, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(0, 0, 60), System.Web.Caching.CacheItemPriority.Default, null);
    }
    else
        datestamps = (ArrayList)Cache["datestamps"];

    foreach(DateTime dt in datestamps)
        Response.Write(dt.ToString() + "<br />");
}
Try running this example and reloading the page. 3 instances of the current date is placed in an ArrayList, and the list is then cached using the Cache object. On each page load, the Cache is checked to see if it contains our ArrayList, using a name we have provided. If it's not, the list is generated, filled and cached. If the ArrayList is already in the cache, we pull it out and cast it to the correct type (everything is stored as object types). No matter where we get the list from, we iterate through it and output each value.

Most of it should be pretty straight forward, except for the line where we add the list to the Cache. The Add method takes a bunch of parameters, and I will try to explain all of them.

First of all, the key we wish to store our object by, in this case we simply call it "datestamps". The key is used to get the object back from the Cache.

Next parameter is the object we wish to cache, so that goes without explaining.

Next up is the CacheDependency parameter. It can be used to tell ASP.NET that the cached item depends on other items, allowing ASP.NET to invalidate the cache if one of these items changes.

The following two parameters tells ASP.NET how and when the item should expire in the cache. The first one specifies an absolute expiration, meaning that the item will expire at a certain time of day. This is usually not what you want, so we set it to NoAbsoluteExpiration. Next we can specify a sliding expiration, which means that the item will expire after a certain amount of time, based on when the item is placed in the cache. The TimeSpan class is used, and we specify that it should expire after 0 hours, 0 minutes and 60 seconds. A priority can be set for the item in the cache. This is used when ASP.NET is removing items from the cache - items with a lower priority are removed first.

The last parameter allows us to specify a callback function for the item, which will be called once the item is removed from the cache, in case you need that. We simply specify a null value.

So, as you can see, storing items by using the Cache object is really easy. Of course, we don't really earn any performance in this example, but only the imagination is the limit here. One of the most common practices are storing objects retrieved from a database in the cache, so save resources on the database machine and allow for faster loading pages.

OutputCache - Substitution

With ASP.NET version 1.0 and 1.1, there was no way to control which parts of a page would be cached, and more importantly: Which parts would be generated on each request no matter what. That meant that whenever you needed just a small part of the page to refreshed on each request, the OutputCache directive could not be used. This has changed with ASP.NET 2.0, where we may use the tag to make areas exist outside the cached content. Have a look at the following example:
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ OutputCache duration="120" varybyparam="None" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Caching</title>
</head>
<body>
    <form id="form1" runat="server">
        Cached datestamp:<br />
        <%= DateTime.Now.ToString() %><br /><br />
        Fresh datestamp:<br />
        <asp:Substitution runat="server" id="UnCachedArea" methodname="GetFreshDateTime" />
    </form>
</body>
</html> 
The Substitution tag takes an attribute called methodname, which holds the name of a method which should return the string to output. Once the page is loaded, no matter if it's returned from the cache or freshly generated, this method will be called, and the Substitution control will be filled with the returned string. Here is the CodeBehind, where you will see our GetFreshDateTime method:
using System;
using System.Data;
using System.Web;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    protected static string GetFreshDateTime(HttpContext context)
    {
        return DateTime.Now.ToString();
    }
}
Since the GetFreshDateTime method needs to be called by the Substitution control, it needs to "look" a certain way - it has to take the HttpContext as a parameter, it has to return a string, and it has to be static. Now, the HttpContext allows you to access all kinds of information about the request etc. to use for returning the proper value. For now, we simply return the current datetime. Run the example, and see how the first datestamp is cached, while the second is reloaded each time. It's as simple as that!

OutputCache - more examples

In the last chapter, we looked at using the OutputCache directive to cache our page very simply. In this chapter, we will look into other ways of using the OutputCache. We used varybyparam in the previous example, but you can vary your cache by other factors as well. Here is a brief list and some examples.

OutputCache - varybyparam

Please see the previous chapter for more information on the varybyparam parameter.

OutputCache - varybycontrol


The varybycontrol does exactly what it says - it varies the cache depending on the value of the specified control. For instance, you can have a dropdownlist with a set of selections, and base the content of the page based on the selected item. In that case, it will make sense to vary by the value of this control, since the content of the page changes according to it. Here is an example of using the varybycontrol parameter:

<%@ OutputCache duration="10" varybyparam="none" varybycontrol="NameOfControl" %>

OutputCache - varybycustom


This is probably the least easy way of using the OutputCache system, but on the other hand, probably the most flexible. It allows you to handle the variations your self, by setting a custom string, which ASP.NET will vary the output by. To test this, you need to add a global.asax file to your project, if you don't already have one. Right click on your project in the Solution Explorer, and select Add new item. Now select the "Global Application Class" and click Ok. In the Global.asax file, you need to override the GetVaryByCustomString like this:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
    if(custom == "Browser")
    {
        return context.Request.Browser.Browser;
    }
    return String.Empty;
}
In this case, our caching will be varied based on which browser the user accesses the page with. The markup part should be written like this:
<%@ OutputCache duration="120" varybyparam="None" varybycustom="Browser" %>
Try accessing the page from different browsers. You will see that the output now depends on which browser you use. The Browser object comes with a bunch of useful information about the client browser - for instance you could vary by whether or not the browser supports CSS, JavaScript or something else.

OutputCache - varybyheader


This one allows you to vary the content based on one or more of the headers that browser send. Here is an example:
<%@ OutputCache duration="120" varybyparam="None" varybyheader="Accept-Language" %>
This will vary cache based on the Accept-Language header, which tells the server which languages the user accepts and prefers

OutputCache

In this chapter, we will take a look at the OutputCache directive, which is by far the easiest way of caching content with ASP.NET. As you will see in our example, it doesn’t even require any code – only some minor changes to the markup of the page, and you’re good to go. In the next chapter, we will look into more ways of using the OuputCachce directive.

Here is a very simple example of a page which will show us the difference between a cached page and a non-cached page. Try creating a new project, and change the Default.aspx page to contain the following markup:

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Caching</title>
</head>
<body>
    <form id="form1" runat="server">
        <%= DateTime.Now.ToString() %>
    </form>
</body>
</html>
This is all standard stuff, except the line with the DateTime. It simply outputs the current date and time to the page. Try running the project and reload the page a couple of times. As you will see, the time is refreshed on each reload. Now, add the following line as line number 2 to our example:
<%@ OutputCache duration="10" varybyparam="None" %>
Run our project again, and reload the page a number of times. As you will see, the time is only refreshed every 10 seconds. Adding caching to your page is as simple as that! Now, the duration parameter is pretty obvious - it tells the page how many seconds to cache the content. Each time the page is requested, ASP.NET checks if the page is in the cache, and if it is, whether or not it has expired. It's served from the cache if it isn't expired - if it is, the page is removed from the cache and the page is generated from scratch and then placed in the cache.

The varybyparam is a required parameter of the OutputCache directive. It specifies a list of parameters which the the cache should be varied by. For instance, if you set it to "p", the cache is now depending on the value of the parameter p. Try changing our example to something like this:
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ OutputCache duration="10" varybyparam="p" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Caching</title>
</head>
<body>
    <form id="form1" runat="server">
        <%= DateTime.Now.ToString() %><br />
        <a href="?p=1">1</a><br />
        <a href="?p=2">2</a><br />
        <a href="?p=3">3</a><br />
    </form>
</body>
</html>
Now, run our example again, and try clicking the links. They each now have their own timestamp, based on when you first accessed the page. The cache is depending on the value of the p parameter! You can specify multiple parameters by seperating them with a semicolon.

Introduction to caching



One of the really cool features of ASP.NET is the caching. With other technologies, caching usually requires some extra software or at least complicated code, but with ASP.NET 2.0, it's easier than ever before. You can use two different kinds of caching - output caching and standard caching. The first one is the easiest, so let's start with that. In the following chapters we will use various forms of the OutputCache directive, as well as the ASP.NET Cache object. Read on.

More validation

The validators all share a couple of attributes, which can be very useful in some cases.

ValidationGroup

This attribute was introduced with ASP.NET 2.0, and makes it possible to divide your form elements into groups. Usually, a validator control is always triggered on a postback, which could sometimes lead to problems. For instance, if you have a contact form and a search field on the same page, the validation of the contact form could be triggered by the Search button, preventing the user from searching before filling out the contact form. You can assign a name in the validationgroup property, for both the validators and the button(s) that you wish to be able to trigger the validation. The value of the attribute can be a number or a name, like validationgroup="contact_form".

SetFocusOnError (true|false)

This attribute was also introduced with ASP.NET 2.0, and it does exactly what the name implies. Set SetFocusOnError to true on one or several of your validators, to give focus to the first invalid field when the form is validated.

Display (Dynamic|None|Static)

This attribute decides how the validator is rendered to your page. The default value is Static, which makes the validator take up the required place whether it's visible (active) or not. You can test this by placing a piece of text directly behind a validator and load the page. If you have not set the Display attribute, or if you have set it to Static, you will see that the text is moved. However, if you set it to Dynamic, the validator will only take up any space if the validation fails and the validator is activated. This can be convenient in some cases, where you need the space the validator can take up otherwise. If you set it to None, the error message will never be shown.

Validation - CustomValidator

If none of the other validators can help you, the CustomValidator usually can. It doesn't come with a predefined way of working; you write the code for validating your self. This is of course very powerful, since the possibilities are basically endless. A common way of using the CustomValidator is when you need to make a database lookup to see if the value is valid. Since this tutorial hasn't treated database access yet, we will do a simpler example, but hopefully you will see that you can do just about everything with the CustomValidator. The control allows you to validate both clientside and serverside, where the serverside approach is probably the most powerful. Of course, doing serverside validation requires a postback to validate, but in most cases, that's not really a problem.

In this example, we will simply check the length of the string in the TextBox. This is a very basic and that useful example, only made to show you how you may use the CustomValidator.

Custom text:<br />
<asp:TextBox runat="server" id="txtCustom" />
<asp:CustomValidator runat="server" id="cusCustom" controltovalidate="txtCustom" onservervalidate="cusCustom_ServerValidate" errormessage="The text must be exactly 8 characters long!" />
<br /><br />
As you can see, it's pretty simple. The only unknown property is the onservervalidate event. It's used to reference a method from CodeBehind which will handle the validation. Switch to our CodeBehind file and add the following method:
protected void cusCustom_ServerValidate(object sender, ServerValidateEventArgs e)
{
    if(e.Value.Length == 8)
        e.IsValid = true;
    else
        e.IsValid = false;
}
This is very simple. The validator basically works by setting the e.IsValid boolean value to either true or false. Here we check the e.Value, which is the string of the control being validated, for it's length. If it's exactly 8 characters long, we return true, otherwise we return false.

Although the serverside approach is probably the most powerful, you need to consider your site hosting, especially if your database receives plenty of queries.