2012-02-23 17 views
6

Qualcuno sa perché se i cookie sono nella mia pagina, la cache di output non funziona!asp.net outputcache e cookies

pagina Esempio

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="ct.aspx.vb" Inherits="ct" %> 
<%@ OutputCache Duration="600" Location="Server" VaryByParam="none" %> 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head runat="server"> 
    <title></title> 
</head> 
<body> 
    <form id="form1" runat="server"> 
    <div> 
     <h1>Cache test</h1> 
     <p id="rndout" runat="server"></p> 
    </div> 
    </form> 
</body> 
</html> 

codice Esempio dietro

Partial Class ct 
    Inherits System.Web.UI.Page 

    Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load 
     Dim rc As New Random() 
     Dim rn As Integer 
     rn = rc.Next() 
     rndout.InnerHtml = rn.ToString 

     Response.Cookies("sym")("hello") = "world" 
     Response.Cookies("sym").Expires = DateTime.Now.AddDays(370) 
     Response.Cookies("sym").Domain = Application.Get("cookieurl") 


    End Sub 
End Class 

quando utilizzato a IIS 6 o 7 questo non cache, se io commento le linee 3 Response.Cookies lo fa.

Quando viene eseguito in VS funziona perfettamente in entrambe le direzioni.

C'è qualche impostazione in iis/web.config ecc per consentire outputcache mentre ho impostato response.cookies. Capisco che il contenuto dei cookie sarà memorizzato nella cache e che è solo una parte della risposta http che viene memorizzata nella cache.

Grazie

Symeon.

+0

Forse vigilia r trovato una soluzione? – Allov

+1

Ho trovato la stessa cosa vera ma non ho riscontrato documenti ufficiali. affermando esplicitamente che non funziona. – JNappi

+0

@ Allov, mi dispiace per il ritardo - no non ho una soluzione. Tranne per eliminare il cookie o se ho bisogno di un cookie, posso aggiungere un tag script o un'immagine 0x0 nella pagina che imposta il cookie. –

risposta

4

Si tenta di memorizzare la cache sul lato server, e allo stesso tempo si tenta di impostare il cookie sul client - questo non funziona insieme.

Perché: quando si imposta una pagina sulla cache sul lato server, il codice sottostante non viene eseguito quando viene fornita la versione memorizzata nella cache (invia al client). Questo è il punto di memorizzazione nella cache sul server. Per non eseguire nulla e darlo dalla cache così com'è.

Forse è sufficiente impostare la cache sull'intestazione e non memorizzare nella cache l'intera pagina sul server.

+1

Sto creando una pagina in asp.net che ha un cookie. Voglio che iis memorizzi nella cache questa pagina e non esegua il codice. Sto usando il codice .net standard per farlo. Comunque sembra che io uso response.cookie in qualsiasi modo la direttiva outputcache sia rotta. Questo non è documentato in alcun modo all'interno di .net. in effetti c'è un articolo che dice che se si memorizza nella cache una pagina con i cookie, anche i cookie vengono memorizzati nella cache. Sono ben consapevole del fatto che il cookie fa parte delle intestazioni http e quindi verrà memorizzato nella cache. la mia domanda è se c'è un'impostazione in iis/web.config ecc che abilita questo. Funziona bene quando si esegue in cassini –

+0

@Symeon questo non è logico (buggy) ciò che si tenta di fare. Hai impostato un cookie per un utente, per quanto riguarda il prossimo utente che non ha alcun cookie impostato? Il cookie impostato sul client - hai mescolato la cache del client con la cache del server. I cookie rimangono anche nella cache quando sono sul lato client e non sul server – Aristos

+1

Chiunque visiti la pagina riceverà un cookie, indipendentemente dal fatto che esista o meno. Un cookie è solo testo in un'intestazione http. Posso capire perché potrebbe essere fonte di confusione, ma ho solo pensato che ci doveva essere una qualche configurazione come no dove si afferma che si escludono a vicenda, e funziona bene in cassini.guarda questo -http: //support.microsoft.com/kb/917072 suona come se DOVREBBE essere il caching con il cookie in quanto forniscono una soluzione alternativa per fermarlo. –

0

Avevo lo stesso problema e ho testato lo scenario fornito da Aristos impostando Location = "ServerAndClient" e funziona. Se utilizzo solo Location = "Server", allora non ha funzionato.

+0

Nel tuo caso, funzionerà solo il client (caching dell'intestazione della risposta HTTP). L'output della pagina non verrà memorizzato nella cache sul server se si impostano i cookie nella risposta. – d4n3

1

Verificare se si sta eseguendo .NET 2.0 SP1 e se è stato applicato MS11-100 (rilasciato a dicembre 2012).

Abbiamo affrontato problemi simili e abbiamo contattato l'assistenza Microsoft. Hanno confermato che MS11-100 interrompe il caching dell'output, ma ha affermato che era di progettazione (a causa della natura delle vulnerabilità di sicurezza corrette nella patch) e attualmente non viene fatto nulla per ripristinare la funzionalità della cache di output.

Un semplice test: se si trova la patch installata, è sufficiente disinstallarla e riavviare. Dovresti vedere che il caching dell'output inizia a funzionare. Non credo che qualcuno lo consiglierebbe come una soluzione di produzione a causa delle implicazioni sulla sicurezza, quindi utilizzalo solo come mezzo per isolare il problema.

Abbiamo finito per testare un nuovo framework (devi andare su 4.0, 3.5 è solo un'estensione del framework 2.0 e non un framework autonomo da solo) e, dopo aver risolto tutti gli errori di compilazione, il caching dell'output ha iniziato a funzionare immediatamente .

Abbiamo anche lavorato per modificare il modo in cui interagiamo con i cookie in modo da poter rimanere sul framework 2.0 (dopo tutto, dovrebbe essere più semplice testare le classi di gestori di cookie invece di testare l'intera applicazione). Ci sono un certo numero di ostacoli e il prodotto finale puzzava di "hack", quindi era un no-go.

2

È causato da diverse versioni di .NET framework. In sostanza, alcune versioni non memorizzeranno mai nella cache la pagina con il set di cookie.

See this blog posting.

+0

Benvenuti in Stack Overflow! Grazie per aver postato la tua risposta! Si prega di leggere attentamente le [FAQ sulla promozione di sé] (http://stackoverflow.com/faq#promotion) attentamente. Si noti inoltre che * è * richiesto * di pubblicare un disclaimer ogni volta che si collega al proprio sito/prodotto. –

-1

C'è una soluzione che potrebbe funzionare in alcuni scenari: Se il cookie non dipende pesantemente sul codice della pagina, ma può essere calcolato con un po 'di codice autonomo, è possibile impostare il cookie nel Application_EndRequest L'Application_EndRequest viene elaborato dopo OutputCache e quindi la cache viene memorizzata senza cookie, ma successivamente viene aggiunta l'intestazione del cookie set prima che la richiesta venga consegnata al client.

+0

Ho provato questo metodo e ho ricevuto un messaggio di errore "Impossibile modificare le intestazioni dopo che la risposta è stata inviata". – WiseGuyEh

2

Dopo aver fatto un bel po 'di ricerche su questo problema, ho capito e risolto il problema.

La cache di output ragione non gioca sempre pulito con biscotti

Quindi la ragione la cache di output non memorizzare nella cache una risposta con i biscotti è che un cookie potrebbe essere user-specifico (ad esempio l'autenticazione, il monitoraggio analitico, eccetera.). Se uno o più cookie con la proprietà HttpCookie.Shareable = false, la cache di output considera la risposta non memorizzabile.

Compreso biscotti con una risposta in cache

Questo è dove ottiene di complicato. La cache di output memorizza nella cache le intestazioni di risposta e il contenuto e non fornisce alcun hook per modificarli prima di inviarli all'utente. Tuttavia, ho scritto il seguente fornitore di cache di output personalizzati per fornire la capacità di modificare le intestazioni di una risposta in cache prima di essere inviati indietro per l'utente (richiede l'Fasterflect NuGet pacchetto):

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.Caching; 
using System.Web; 
using System.Web.Caching; 
using Fasterflect; 

namespace CustomOutputCache 
{ 
    /// <summary> 
    /// An output cache provider that has ability to modify the http header collection before a cached response is served back to the user. 
    /// </summary> 
    public class HeaderModOutputCacheProvider : OutputCacheProvider 
    { 
     private static readonly Type OutputCacheEntryType, HttpCachePolicySettingsType; 
     private static readonly Type[] ParameterTypes; 

     public static event EventHandler<CachedRequestEventArgs> RequestServedFromCache; 

     static HeaderModOutputCacheProvider() 
     { 
      var systemWeb = typeof(HttpContext).Assembly; 
      OutputCacheEntryType = systemWeb.GetType("System.Web.Caching.OutputCacheEntry"); 
      HttpCachePolicySettingsType = systemWeb.GetType("System.Web.HttpCachePolicySettings"); 
      ParameterTypes = new[]{ 
       typeof(Guid), 
       HttpCachePolicySettingsType, 
       typeof(string), 
       typeof(string) , 
       typeof(string[]), 
       typeof(int), 
       typeof(string), 
       typeof(List<HeaderElement>), 
       typeof(List<ResponseElement>) 
      }; 
     } 

     private readonly ObjectCache _objectCache; 

     public HeaderModOutputCacheProvider() 
     { 
      _objectCache = new MemoryCache("output-cache"); 
     } 

     #region OutputCacheProvider implementation 

     public override object Get(string key) 
     { 
      var cachedValue = _objectCache.Get(key); 

      if (cachedValue == null) 
       return null; 

      if (cachedValue.GetType() != OutputCacheEntryType) 
       return cachedValue; 

      var cloned = CloneOutputCacheEntry(cachedValue); 

      if (RequestServedFromCache != null) 
      { 
       var args = new CachedRequestEventArgs(cloned.HeaderElements); 
       RequestServedFromCache(this, args); 
      } 

      return cloned; 
     } 

     public override object Add(string key, object entry, DateTime utcExpiry) 
     { 
      _objectCache.Set(key, entry, new CacheItemPolicy { AbsoluteExpiration = utcExpiry }); 
      return entry; 
     } 

     public override void Set(string key, object entry, DateTime utcExpiry) 
     { 
      _objectCache.Set(key, entry, new CacheItemPolicy { AbsoluteExpiration = utcExpiry }); 
     } 

     public override void Remove(string key) 
     { 
      _objectCache.Remove(key); 
     } 

     #endregion 

     private IOutputCacheEntry CloneOutputCacheEntry(object toClone) 
     { 
      var parameterValues = new[] 
      { 
       toClone.GetFieldValue("_cachedVaryId", Flags.InstancePrivate), 
       toClone.GetFieldValue("_settings", Flags.InstancePrivate), 
       toClone.GetFieldValue("_kernelCacheUrl", Flags.InstancePrivate), 
       toClone.GetFieldValue("_dependenciesKey", Flags.InstancePrivate), 
       toClone.GetFieldValue("_dependencies", Flags.InstancePrivate), 
       toClone.GetFieldValue("_statusCode", Flags.InstancePrivate), 
       toClone.GetFieldValue("_statusDescription", Flags.InstancePrivate), 
       CloneHeaders((List<HeaderElement>)toClone.GetFieldValue("_headerElements", Flags.InstancePrivate)), 
       toClone.GetFieldValue("_responseElements", Flags.InstancePrivate) 
      }; 

      return (IOutputCacheEntry)OutputCacheEntryType.CreateInstance(
       parameterTypes: ParameterTypes, 
       parameters: parameterValues 
      ); 
     } 

     private List<HeaderElement> CloneHeaders(List<HeaderElement> toClone) 
     { 
      return new List<HeaderElement>(toClone); 
     } 
    } 

    public class CachedRequestEventArgs : EventArgs 
    { 
     public CachedRequestEventArgs(List<HeaderElement> headers) 
     { 
      Headers = headers; 
     } 
     public List<HeaderElement> Headers { get; private set; } 

     public void AddCookies(HttpCookieCollection cookies) 
     { 
      foreach (var cookie in cookies.AllKeys.Select(c => cookies[c])) 
      { 
       //more reflection unpleasantness :(
       var header = cookie.CallMethod("GetSetCookieHeader", Flags.InstanceAnyVisibility, HttpContext.Current); 
       Headers.Add(new HeaderElement((string)header.GetPropertyValue("Name"), (string)header.GetPropertyValue("Value"))); 
      } 
     } 
    } 
} 

Si potrebbe legare esso in questo modo:

<system.web> 
    <caching> 
     <outputCache defaultProvider="HeaderModOutputCacheProvider"> 
     <providers> 
      <add name="HeaderModOutputCacheProvider" type="CustomOutputCache.HeaderModOutputCacheProvider"/> 
     </providers> 
     </outputCache> 
    </caching> 
    </system.web> 

e potrebbe usare in questo modo di inserire i cookie:

HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache; 

HeaderModOutputCacheProvider.RequestServedFromCache += (sender, e) => 
{ 
    e.AddCookies(new HttpCookieCollection 
    { 
     new HttpCookie("key", "value") 
    }); 
};