5
votes

Is there an easy way to cache ASP.NET whole page for anonymous users only (forms authentication used)?

Context: I'm making a website where pages displayed to anonymous users are mostly completely static, but the same pages displayed for logged-in users are not.

Of course I can do this by hand through code behind, but I thought there might be a better/easier/faster way.

3
Did you ever get a resolution to this problem? We have a similar need that varyByCustom is not the answer for. - Nathan Palmer
Currently I use code-behind solution, where I can easily decide if I want to cache the page or not. If the user is not logged in, I cache. If the user is logged in, cache is disabled for a whole page (and caches only "static" parts instead). After I received the answer below, I searched for a solution without code-behind, but found nothing helpful. After all, a code-behind solution is also very clear and does not have major disadvantages over pure ASP.NET one. - Arseni Mourzenko
Could you share your codebehind solution? How do you control the cache like that? - Nathan Palmer
In code, if your page is cached by default, add something like that: if (User.Identity.IsAuthenticated) { Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetExpires(DateTime.Now.AddMinutes(-1)); Response.Cache.SetNoStore(); } Or you can set cache in code if the user is not logged in and avoid setting anything on ASP.NET side. (Sorry for the ugly not indented code. Cannot find how to make newlines in comments...) - Arseni Mourzenko
@MainMa Have you seen this answer? stackoverflow.com/a/4951434/498892 - Alleo

3 Answers

3
votes

I'm using asp.net MVC, so I did this in my controller

if (User.Identity.IsAuthenticated) {
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.Cache.SetExpires(DateTime.Now.AddMinutes(-1));
    Response.Cache.SetNoStore();
    Response.Cache.SetNoServerCaching();
}
else {
    Response.Cache.VaryByParams["id"] = true; // this is a details page
    Response.Cache.SetVaryByCustom("username"); // see global.asax.cs GetVaryByCustomString()
    Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
    Response.Cache.SetCacheability(HttpCacheability.Server);
    Response.Cache.SetValidUntilExpires(true);
}

The reason I did it this way (instead of declaratively) was I also needed the ability to turn it on and off via configuration (not shown here, but there's an extra check in the if for my config variable).

You still need the vary by username, else you'll not execute this code when a logged in user appears. My GetVaryByCustomString function returns "anonymous" when not authenticated or the users name when available.

1
votes

You could use VaryByCustom, and use a key like username.

1
votes

There is nothing stopping you from extending the existing attribute with the desired behaviour,

for example:

public class AnonymousOutputCacheAttribute : OutputCacheAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    {
       if(filterContext.HttpContext.User.Identity.IsAuthenticated)
          return;

        base.OnActionExecuting(filterContext);
    }  
}  

Haven't tested this, but I don't see reason why this shouldn't work.