Advanced ASP.NET Caching and AddValidationCallBack
ASP.NET (today 1.1, and more so with 2.0) has a fantastic capability for caching.
At it's most basic, there's
<%OutputCache Duration="30" VaryByParam="id"%>
When this is added to an ASPX page, it would automatically cache versions of a page for every received value of id= that appears in the QueryString.
That means that when your application starts up, there's nothing in the ASP.NET output cache. If someone hits foo.aspx?id=4, your code-behind executes and the page renders the first time. Subsequent hits to foo.aspx?id=4 will retrieve a cached version. Since Duration="30", that means that your code for foo.aspx will not run until the cached item expires in 30 seconds.
As new visitors hit foo.aspx with different values for id=, there will be a new version cached. You want to be aware of how many possible values for id= there are, as your web servers memory will be affected. If foo.aspx is hit with a few dozen values for id=, you're likely OK. But if there are thousands or millions of potential values and you have a long value for Duration, you may end up holding a lot more versions of cached pages in memory than is reasonable or performant.
In addition to VaryByParam, there's a few others, with the most powerful being VaryByCustom where you can set a custom string:
<%OutputCache Duration="30" VaryByCustom="mycustomthing"%>
Then you override HttpApplication.GetVaryByCustomString in your Global.asax. GetVaryByCustomString returns a string. That string is built by you and used as a key to store and retrieve a cached version of your page. The key can be anything and build from anything. You can create a composite key from other pieces of information available to you like cookies, user-languages, browser capabilities, whatever.
This gives the developer a lot of flexibility as to the name that the developer wants to base caching on. However, what if I want to cache pages for every value of id= except id=5?
That's where the little-used, little-known, Response.Cache.AddValidationCallback comes in.
On your page you hook up a callback that will be called when it's time to decide whether to return a cached version of your page.
<%@ OutputCache VaryByParam="none" Duration=600 %>
<Script Language="C#" runat="server">
public void Page_Load()
Response.Cache.AddValidationCallback(new HttpCacheValidateHandler(Validate), "somecustomdata");
public void Validate(HttpContext context, Object data, ref HttpValidationStatus status)
//I can check 'data' if I want to here as well...
if (context.Request.QueryString["id"] == "5")
status = HttpValidationStatus.IgnoreThisRequest;
status = HttpValidationStatus.Valid;
There are three values for HttpValidationStatus. In this example, if id=5, HttpValidationStatus.IgnoreThisRequest indicates that this should be treated as a Cache Miss and the page will run and render as usual. If not, HttpValidationStatus.Valid indicates that everything is cool. The third value, not shown here, is HttpValidationStatus.Invalid that indicates not only that this request should be treated as a Cache Miss, but also that any cached value should be invalidated and evicted from the Output Cache.
Note: You don't want to do ANYTHING "heavy" in the callback method. Remember that your callback is being called to ask your advice. ASP.NET is asking, "should I return the cached item?" If it takes you longer to answer that question then it would to just return the cached item, then you need to rethink what are your goals. Remember also that you can store some small objects (context) when you setup the callback that may be used later to make your decision.
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
Comments are closed.