Asp.net mvc 如何在ASP.NET MVC中为经过身份验证的用户关闭输出缓存?
我有一个ASP.NETMVC应用程序。我需要缓存一些页面,但是仅针对未经身份验证的用户 我尝试将Asp.net mvc 如何在ASP.NET MVC中为经过身份验证的用户关闭输出缓存?,asp.net-mvc,outputcache,Asp.net Mvc,Outputcache,我有一个ASP.NETMVC应用程序。我需要缓存一些页面,但是仅针对未经身份验证的用户 我尝试将VaryByCustom=“user”与以下GetVaryByCustomString实现结合使用: public override string GetVaryByCustomString(HttpContext context, string custom) { if (custom == "user") { if (context.User.Identity.IsAuthen
VaryByCustom=“user”
与以下GetVaryByCustomString
实现结合使用:
public override string GetVaryByCustomString(HttpContext context, string custom)
{
if (custom == "user")
{
if (context.User.Identity.IsAuthenticated)
{
return context.User.Identity.Name;
}
else
{
return "";
}
}
return base.GetVaryByCustomString(context, custom);
}
然而,这并不是我所需要的,因为页面仍然是缓存的。唯一的区别是,现在分别为每个用户缓存
一种可能的解决方案是每次用户通过身份验证时都返回Guid.NewGuid()
,但对我来说,这似乎是一种巨大的资源浪费
你有什么建议给我吗?下面是我做的:
public class NonAuthenticatedOnlyCacheAttribute : OutputCacheAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var httpContext = filterContext.HttpContext;
if (httpContext.User.Identity.IsAuthenticated)
{
// it's crucial not to cache Authenticated content
Location = OutputCacheLocation.None;
}
// this smells a little but it works
httpContext.Response.Cache.AddValidationCallback(IgnoreAuthenticated, null);
base.OnResultExecuting(filterContext);
}
// 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)
{
if (context.User.Identity.IsAuthenticated)
validationStatus = HttpValidationStatus.IgnoreThisRequest;
else
validationStatus = HttpValidationStatus.Valid;
}
}
非常感谢为我指出正确方向的人,我无意中否决了他的回答。属性一般都是缓存的,然后需要存储原始位置。如果您访问记录的页面,它会将Location设置为None,那么当您以匿名方式访问时,它仍然是None
public class AuthenticatedOnServerCacheAttribute : OutputCacheAttribute
{
private OutputCacheLocation? originalLocation;
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var httpContext = filterContext.HttpContext;
if (httpContext.User.Identity.IsAuthenticated)
{
originalLocation = originalLocation ?? Location;
Location = OutputCacheLocation.None;
}
else
{
Location = originalLocation ?? Location;
}
base.OnResultExecuting(filterContext);
}
}
公认的答案是正确的,但它不适用于以这种方式缓存部分视图。 我结合了两种变体:
GetVaryByCustomString
并将Duration
设置为最小值-对于部分视图和页面的AddValidationCallback
方法。实际上,只使用第一种方法是可能的,但第二种方法看起来并不昂贵——它不会每次调用OnResultExecuting
,而是只调用注册的处理程序
因此,自定义缓存属性类
public class CacheAttribute : OutputCacheAttribute
{
public CacheAttribute()
{
Duration = 300; /*default cache time*/
}
private bool _partialView;
/// <summary>
/// Set true if Partial view is cached
/// </summary>
public bool PartialView
{
get { return _partialView; }
set
{
_partialView = value;
if ( _partialView ) {
VaryByCustom = "Auth";
}
}
}
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;
}
}
像这样使用它:
[Cache]
public virtual ActionResult Index()
{
return PartialView();
}
[ChildActionOnly, Cache(PartialView=true)]
public virtual ActionResult IndexPartial()
{
return PartialView();
}
更新:我也在这里添加了Fujiy的补丁有趣-自从这篇文章(1年前)以来,你对这个方法有什么问题吗?Thanks@UpTheCreek:我们在产品中使用了稍微复杂一点的代码版本。显然,我什么也不保证,但以我的经验来看,它是有效的。它对页面非常有效,但不幸的是,对部分视图不起作用-1。这行不通。一旦为经过身份验证的请求执行此逻辑,所有后续请求都将没有缓存。请记住,该属性是一个在AppDomain生命周期内存在的单个实例,跨越所有HttpApplication实例。要从每个请求的FilterAttribute更改缓存行为,必须重新实现base.OnResultExecuting中的逻辑,以便为Page.InitOutputCache提供单独的实例。请参阅source.gWiz是正确的——一旦您在IsAuthenticated检查中设置了位置,所有后续请求都不会被缓存。要解决这个问题,可以像这样缓存原始位置:然后将其用于未经验证的请求…但是您仍然需要接受答案中的“IgnoreAuthenticated”部分
[Cache]
public virtual ActionResult Index()
{
return PartialView();
}
[ChildActionOnly, Cache(PartialView=true)]
public virtual ActionResult IndexPartial()
{
return PartialView();
}