When we pushed out Telerik TV, we ran into an interesting style issue.  We were using output caching on our index page to save the server a little work.  However, sometimes when a user navigated to tv.telerik.com/home it would look like this:


This problem would only manifest itself on the production server, and shockingly there were no errors! By looking at the source of the page we quickly realized that neither the StyleSheetRegistrar, nor the ScriptRegistrar were outputting anything at all.  This made it clear that the Render method on the StyleSheetRegistrar / ScriptRegistrar was not firing, or something was causing them to fail. I decided to take a look at the Render method of the StylesheetRegistrar:

   1: public void Render()
   2: {  
   3: if (hasRendered)  
   4:     {       
   5: throw new InvalidOperationException(Resources.TextResource.YouCannotCallRenderMoreThanOnce);   
   6:     }   
   7: if (ViewContext.HttpContext.Request.Browser.SupportsCss)   
   8:     {   
   9:         Write(ViewContext.HttpContext.Response.Output);   
  10:     } 
  12:     hasRendered = true;
  13: }

Looking at lines 7-10 of the Render method, we immediately realized our mistake.  We were output caching the page no matter what (not varying by header, param, etc).  If a web crawler that does not support CSS hit the page first after the cache timeout, then that is the version of the page that would be cached. And as you can see from the Render method, if the browser does not support CSS, the StyleSheetRegistrar does not output anything.(Why should it?)  The ScriptRegistrar’s Render method looks much the same.


The Fix

There is actually an easy way to fix this issue.  All we needed to do was vary the output cache based on whether Css/script are supported by the browser.


To do this, add the following attribute to your controller action:

[OutputCache(VaryByParam="none", VaryByCustom = "MyCustomRuleKey", Duration = 3600)]

and in your global.asax:

public override string GetVaryByCustomString(HttpContext context, string customCacheRuleName)
if (String.Compare(customCacheRuleName, "MyCustomRuleKey") == 0)
return Request.Browser.SupportsCss.ToString();
return base.GetVaryByCustomString(context, customCacheRuleName);

Using the GetVaryByCustomString method of the Global.asax, you can easily cache different versions of your page by returning a unique key based on criteria of your choosing.  This simple implementation would cache 2 different pages, one with CSS styles, and one without styles.  


Happy coding!

About the Author

Atanas Korchev

 is Team Leader in Kendo UI Team

Related Posts


Comments are disabled in preview mode.