2012-02-23 16 views
6

¿Alguien sabe por qué si hay cookies en mi página, el caché de salida no funciona!asp.net outputcache y cookies

Ejemplo de página

<%@ 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> 

código Ejemplo detrás

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 

cuando se despliegan en IIS 6 o 7 esto no caché, sin embargo si me comente las líneas 3 Response.Cookies lo hace.

Cuando se ejecuta en VS funciona bien en ambos sentidos.

Hay alguna configuración en iis/web.config, etc. para permitir el almacenamiento de salida mientras configuro response.cookies. Entiendo que el contenido de la cookie se almacenará en caché y que solo forma parte de la respuesta http almacenada en caché.

Gracias

Symeon.

+0

Sabía usted víspera ¿Encontró una solución? – Allov

+1

Encontré lo mismo para ser cierto pero no he encontrado ningún documento oficial. declarando explícitamente que no funciona. – JNappi

+0

@Allov, perdón por el retraso: no, no tengo una solución. Excepto para deshacerse de la cookie o si necesito una cookie, puedo agregar una etiqueta de script o una imagen de 0x0 en la página que solo establece la cookie. –

Respuesta

4

Intenta almacenar en caché esto del lado del servidor y, al mismo tiempo, intenta establecer la cookie en el cliente; esto no funciona en conjunto.

Por qué: Cuando configura una página en la memoria caché del lado del servidor, el código subyacente no se ejecuta cuando se sirve la versión en caché (se envía al cliente). Este es el punto de almacenamiento en caché en el servidor. Para no ejecutar nada y darlo desde la memoria caché tal como está.

Quizás necesite simplemente configurar la caché en el encabezado y no almacenar en caché la página completa en el servidor.

+1

Estoy creando una página en asp.net que tiene una cookie. Quiero que iis guarde en caché esta página y no ejecute el código detrás. Estoy usando el código .net estándar para hacer esto. Sin embargo, parece que si uso response.cookie de alguna manera la directiva outputcache está en quiebra. Esto no está documentado de ninguna manera dentro de .net. de hecho, hay un artículo que dice: recuerde que si guarda en caché una página con cookies, las cookies también se almacenarán en caché. Soy consciente de que la cookie forma parte de los encabezados http y, por lo tanto, se almacenará en caché. mi pregunta es si hay una configuración en iis/web.config etc. que lo habilite. Funciona bien cuando se ejecuta en cassini –

+0

@Symeon esto no es lógico (con errores) lo que intenta hacer. Establece una cookie para un usuario, ¿qué pasa con el siguiente usuario que no tiene cookies? La cookie establecida en el cliente: ha confundido el caché del cliente con el caché del servidor. Las cookies también se mantienen en la memoria caché cuando están en el lado del cliente, no en el servidor – Aristos

+1

Quien visita la página recibirá una cookie, ya sea que exista o no. Una cookie es solo texto en un encabezado http. Puedo ver por qué puede ser confuso, pero pensé que debe haber habido alguna configuración, ya que no dice que son mutuamente excluyentes, y funciona bien en cassini.mira esto -http: //support.microsoft.com/kb/917072 suena como que DEBERÍA estar almacenando en la memoria caché con la cookie, ya que ofrecen una solución para detenerlo. –

0

Estaba teniendo el mismo problema y probé la situación dada por Aristos estableciendo Location = "ServerAndClient" y funciona. Si solo uso Location = "Server", no funcionó.

+0

En su caso, solo funcionará el cliente (caché de encabezado de respuesta HTTP). El resultado de la página no se almacenará en caché en el servidor si configura las cookies en su respuesta. – d4n3

1

Compruebe si está ejecutando .NET 2.0 SP1 y si ha aplicado MS11-100 (lanzado en diciembre de 2012).

Tuvimos problemas similares y terminamos contactando con Microsoft Support. Confirmaron que MS11-100 rompe el almacenamiento en caché de resultados, pero afirmaron que fue por diseño (debido a la naturaleza de las vulnerabilidades de seguridad corregidas en el parche) y que actualmente no se está haciendo nada para restaurar la funcionalidad del caché de resultados.

Una prueba simple: si encuentra que tiene el parche instalado, simplemente desinstale ese parche y reinicie. Debería ver que el almacenamiento en caché de salida comienza a funcionar. No creo que nadie lo recomiende como una solución de producción debido a las implicaciones de seguridad, así que solo use esto como un medio para aislar el problema. Terminamos probando un marco más nuevo (debe ir a 4.0; 3.5 es solo una extensión del marco 2.0 y no un marco independiente) y, después de resolver todos los errores de compilación, el caché de resultados comenzó a funcionar inmediatamente .

También trabajamos en cambiar la forma en que interactuamos con las cookies para poder permanecer en el marco 2.0 (después de todo, debería ser más fácil probar nuestras clases de manejador de cookies en lugar de probar toda la aplicación). Hay una serie de obstáculos y el producto final apestaba a "hacks", por lo que era un no-go.

2

Es causado por diferentes versiones de .NET framework. Básicamente, algunas versiones nunca almacenarán en caché la página con el conjunto de cookies.

See this blog posting.

+0

¡Bienvenido a Stack Overflow! ¡Gracias por publicar tu respuesta! Asegúrese de leer detenidamente [Preguntas frecuentes sobre autopromoción] (http://stackoverflow.com/faq#promotion). También tenga en cuenta que * se requiere * que publique un descargo de responsabilidad cada vez que se vincula a su propio sitio/producto. –

-1

Hay una solución que podría funcionar en algunos escenarios: Si la cookie no depende en gran medida del código de la página, pero se puede calcular con algo de código independiente, puede establecer la cookie en el Application_EndRequest El Application_EndRequest se procesa después OutputCache y, por lo tanto, el caché se almacena sin cookies, pero luego se agrega el encabezado de cookies establecido antes de que la solicitud se entregue al cliente.

+0

Intenté este método y recibí un "no puedo modificar los encabezados después de que se envió el error de respuesta". – WiseGuyEh

2

Después de hacer un poco de investigación sobre este problema, llegué a comprender y solucionar el problema.

El caché de resultados razón no se lleva bien con galletas

Así que la razón de la caché de resultados no cachear una respuesta con las cookies es que una cookie podría ser específica del usuario (por ejemplo, la autenticación, el seguimiento analítico, etc.). Si hay una o más cookies con la propiedad HttpCookie.Shareable = false, la memoria caché de resultados considera que la respuesta no se puede descartar.

Incluyendo las galletas con una respuesta en caché

Esto es en donde está difícil de conseguir. La memoria caché de resultados almacena en caché los encabezados y el contenido de la respuesta juntos y no proporciona ningún gancho para modificarlos antes de devolverlos al usuario. Sin embargo, me escribió el siguiente proveedor de memoria caché de salida personalizado para proporcionar la capacidad de modificar las cabeceras de una respuesta en caché antes de ser enviados de vuelta al usuario (requiere la Fasterflect Nuget empaquetar):

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

Usted habría cablearlo de esta manera:

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

y podría utilizar de esta manera para insertar las cookies:

HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache; 

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