2010-01-21 12 views
15

Ich habe eine ASP.NET MVC-Anwendung. Ich muss jedoch einige Seiten zwischenspeichern nur für nicht authentifizierte Benutzer.Wie Deaktivieren des Ausgabezwischenspeichers für authentifizierte Benutzer in ASP.NET MVC?

Ich habe versucht, VaryByCustom="user" mit der folgenden GetVaryByCustomString Implementierung zu verwenden:

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); 
} 

Doch dies ist nicht genau das, was ich brauche, weil Seiten noch zwischengespeichert werden. Einziger Unterschied ist, dass jetzt für jeden Benutzer separat zwischengespeichert wird.

Eine mögliche Lösung ist die Rückgabe Guid.NewGuid() jedes Mal, wenn Benutzer authentifiziert ist, aber es sieht aus wie eine riesige Verschwendung von Ressourcen für mich.

Also hast du irgendwelche Tipps für mich?

Antwort

32

So, hier ist das, was ich getan:

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;   
    } 
} 

Vielen Dank an Craig Stuntz, der mir zeigte Richtung zu korrigieren und deren Antwort ich unwissentlich Downvoted.

+1

Cool! Nette Lösung. –

+0

Interessant - hatten Sie seit diesem Post (vor 1 Jahr) irgendwelche Probleme mit dieser Methode? Danke – UpTheCreek

+0

@UpTheCreek: Wir verwenden etwas kompliziertere Version dieses Codes in unserem Produkt. Natürlich garantiere ich nichts, aber nach meiner Erfahrung funktioniert es. –

12

Attribute im Allgemeinen werden zwischengespeichert, dann müssen Sie den ursprünglichen Speicherort speichern. Wenn Sie auf die Seite "Protokolliert" zugreifen, wird für "Standort" der Wert "Keine" festgelegt. Wenn Sie auf "Anonym" zugreifen, wird "Keine" angezeigt.

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); 
    } 
} 
+2

Dies sollte die akzeptierte Antwort sein. Die Antwort von Jakub funktioniert nicht – Alex

+0

..aber Sie brauchen immer noch den "IgnoreAuthenticated" Teil von der angenommenen Antwort – Alex

2

Die angenommene Antwort ist korrekt, aber auf diese Weise funktioniert es nicht für das Zwischenspeichern Teilansichten. Ich habe beide Varianten kombiniert: GetVaryByCustomString und setzen Duration auf das Minimum - für Teilansichten und AddValidationCallback Methode für Seiten. Tatsächlich ist es möglich, nur die erste Methode zu verwenden, aber die zweite sieht nicht so teuer aus - sie ruft nicht jedes Mal auf, sondern nur registrierte Handler.

So ist die individuelle Cache Attributklasse

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; 
    } 
} 

Aufschalten GetVaryByCustomString Methode in Global.asax.cs

public override string GetVaryByCustomString(HttpContext context, string custom) 
{ 
    if (custom == "Auth") { 
     //do not cache when user is authenticated 
     if (context.User.Identity.IsAuthenticated) { 
     return base.GetVaryByCustomString(context, custom); 
     } 
     return "NotAuth"; 
    }  
    return base.GetVaryByCustomString(context, custom); 
} 

es wie folgt verwendet:

[Cache] 
public virtual ActionResult Index() 
{ 
    return PartialView(); 
} 

[ChildActionOnly, Cache(PartialView=true)] 
public virtual ActionResult IndexPartial() 
{ 
    return PartialView(); 
} 

Aktualisiert: Ich habe auch hinzugefügt Fujiys Fix

Verwandte Themen