I've a ASP.NET MVC application in which I've implemeneted custom caching filter as below code:
public class NonAuthenticatedOnlyCacheAttribute : OutputCacheAttribute
{
public NonAuthenticatedOnlyCacheAttribute()
{
Duration = 600; /*default cache time*/
}
private bool _partialView;
public bool PartialView
{
get { return _partialView; }
set
{
_partialView = value;
if (_partialView)
{
VaryByCustom = "user";
}
}
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
if (PartialView) OnCachePartialEnabled(filterContext);
else OnCacheEnabled(filterContext);
base.OnResultExecuting(filterContext);
}
private OutputCacheLocation? originalLocation;
private int? _prevDuration;
protected void OnCachePartialEnabled(ResultExecutingContext filterContext)
{
var httpContext = filterContext.HttpContext;
if (!_prevDuration.HasValue) _prevDuration = Duration;
Duration = httpContext.User.Identity.IsAuthenticated ? 1 : _prevDuration.Value;
}
protected void OnCacheEnabled(ResultExecutingContext filterContext)
{
var httpContext = filterContext.HttpContext;
if (httpContext.User.Identity.IsAuthenticated)
{
// it's crucial not to cache Authenticated content
originalLocation = originalLocation ?? Location;
Location = OutputCacheLocation.None;
}
else
{
Location = originalLocation ?? Location;
}
// this smells a little but it works
httpContext.Response.Cache.AddValidationCallback(IgnoreAuthenticated, null);
}
// This method is called each time when cached page is going to be
// served and ensures that cache is ignored for authenticated users.
private void IgnoreAuthenticated(HttpContext context, object data, ref HttpValidationStatus validationStatus)
{
validationStatus = context.User.Identity.IsAuthenticated
? HttpValidationStatus.IgnoreThisRequest
: HttpValidationStatus.Valid;
}
}
The problem I'm facing is, even though I'm not caching the page for authenticated user, sometimes I'm seeing a cached page of some other authenticated user. This happens rarely and randomly.
If I debug through this, it works perfectly fine but not when it occurs on LIVE site. What I'm also seeing is, a cookie (".AspNet.ApplicationCookie") of the authenticated user gets created in browser as well. (Does it mean that output cache is also caching response cookies as well?) If I delete this cookie then user gets logged out which is obvious.
In Global.asax, I have following code:
public override string GetVaryByCustomString(HttpContext context, string value)
{
if (value.Equals("culture") || value.Equals("user"))
{
var customString = Thread.CurrentThread.CurrentUICulture.Name;
if (context.User.Identity.IsAuthenticated)
{
customString = $"{context.User.Identity.Name}-{customString}";
}
return customString;
}
return base.GetVaryByCustomString(context, value);
}
And on controller, below attribute is cached
[NonAuthenticatedOnlyCacheAttribute(Location = System.Web.UI.OutputCacheLocation.Server, Duration = 600, VaryByCustom = "user")]
I think the problem may be that you did not tell ASP.NET what you mean with:
VaryByCustom = "user"
Maybe you did that, but the code is not included in your post. In your Global.asax.cs you will have something like:
public override string GetVaryByCustomString(HttpContext context, string arg)
{
if (arg.Equals("User", StringComparison.InvariantCultureIgnoreCase))
{
var user = context.User.Identity.Name; // TODO here you have to pick an unique identifier from the current user identity
return string.Format("{0}@{1}", userIdentifier.Name, userIdentifier.Container);
}
return base.GetVaryByCustomString(context, arg);
}
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments