Stefan Goßner

Senior Escalation Engineer for SharePoint (WSS, SPS, MOSS, SP2010) and MCMS

Blogs

Channel based ASP.NET output caching for user web controls

  • Comments 4
  • Likes

ASP.NET output caching is a mandatory feature for all high performance Web sites. MCMS extends the ASP.NET output caching to allow caching of content based on (e.g.) the Posting and User Context. To allow this MCMS adds new token strings which can be configured using the VaryByCustom property of the OutputCache directive.

Here are some samples on enabling output caching in template files:

  • To cache each posting, specify VaryByCustom="CMSPosting"
  • To cache each posting for each user role, specify VaryByCustom="CMSPosting;CMSRole"

The following sample can be used to enable output caching for user controls:

  • to cache the control independed of the current posting, user or role specify VaryByCustom="CMSControl"
  • to cache a different instance of the control for each posting, specify VaryByCustom="CMSPosting;CMSControl"
  • to cache a different instance of the control for each posting and each user role, specify VaryByCustom="CMSPosting;CMSRole;CMSControl"

There are lot more possible combinations. Please check the MCMS documentation for details.

If you consider the possibilities you will identify that there is one important thing missing: You might have a user control on all your postings which will not vary between different postings in the same channel but will vary between postings in different channels (e.g. navigation controls like the bread crumb control). Such a control will be added to all postings in a channel and also to the channel rendering script. It would be nice if all postings in this channel would use the same cached instance of the control instead of using different cached instances.

You would look for something like VaryByCustom="CMSChannel;CMSControl"

Unfortunatelly MCMS does not provide such a feature out of the box. We will have to extend ASP.NET output caching and add the feature we need.

To do this we need to override the CmsHttpApplication.GetVaryByCustomStringToken method. This method is called for each token in the VaryByCustom property. In this method we have to check if the token coming in is "CMSChannel" and return a unique string - e.g. the GUID of the channel - for each channel. If it is a different token, we will pass the control to the base method to keep the existing functionality.

All of the above is done by the following method which needs to be added to your global.asax.cs:


  protected override string GetVaryByCustomStringToken(HttpContext context, string token)
  {
     if (token.ToLower() == "cmschannel")
        return CmsHttpContext.Current.Channel.Guid;
     else
        return base.GetVaryByCustomStringToken(context, token);
  }

Comments
  • This is exactly what .Text is using now. :)

    -Scott

  • likewise, some content depends on the particular template, or mode. Here is my version...

    protected override string GetVaryByCustomStringToken(HttpContext context, string token)
    {
    string tokenValue;

    switch (token)
    {
    case "cmschannel":
    tokenValue = CmsHttpContext.Current.Channel.Path;
    break;
    case "cmsmode":
    tokenValue = CmsHttpContext.Current.Mode.ToString();
    break;
    case "cmstemplate":
    if (CmsHttpContext.Current.Posting != null)
    {
    tokenValue = CmsHttpContext.Current.Posting.Template.Path;
    break;
    }
    else
    {
    goto default;
    }
    default:
    tokenValue = base.GetVaryByCustomStringToken (context, token);
    break;
    }
    return tokenValue;
    }

Raw Html Fix