2012-02-23 9 views
6

Czy ktoś wie, dlaczego jeśli pliki cookie są na mojej stronie, pamięć podręczna wyjściowa nie działa!asp.net outputcache i ciasteczka

Przykład strona

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

Przykład kodu za

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 

po wdrożeniu do IIS 6 lub 7 to nie cache, jednak jeśli I ustosunkowania się 3 Response.Cookies linii robi.

Po uruchomieniu w VS działa dobrze w obie strony.

Czy jest jakieś ustawienie w iis/web.config etc, aby umożliwić outputcache podczas ustawiania response.cookies. Rozumiem, że zawartość plików cookie zostanie zapisana w pamięci podręcznej, a także stanowi część buforowanej odpowiedzi HTTP.

Dzięki

Symeon.

+0

skończyłeś Ewę r znalazł rozwiązanie? – Allov

+1

Znalazłem to samo, co prawda, ale nie spotkałem żadnych oficjalnych dokumentów. jednoznacznie stwierdzające, że nie działa. – JNappi

+0

@Allov, przepraszam za opóźnienie - nie, nie mam rozwiązania. Oprócz pozbycia się pliku cookie lub jeśli potrzebuję pliku cookie, mogę dodać znacznik skryptu lub obraz 0x0 na stronie, która po prostu ustawia plik cookie. –

Odpowiedz

4

Próbujesz cache to po stronie serwera, a jednocześnie próbujesz ustawić plik cookie na kliencie - to nie działa razem.

Powód: Po ustawieniu strony w pamięci podręcznej po stronie serwera kod nie jest uruchamiany, gdy jest wyświetlana wersja przechowywana w pamięci podręcznej (wysyłanie do klienta). To jest punkt buforowania na serwerze. Aby niczego nie uruchamiać i przekazywać z pamięci podręcznej takim, jaki jest.

Może wystarczy ustawić pamięć podręczną w nagłówku i nie buforować całej strony na serwerze.

+1

Tworzę stronę w asp.net, która ma plik cookie. Chcę, aby iis buforował tę stronę i nie uruchamiał kodu. W tym celu używam standardowego kodu .net. Jednak wygląda na to, że używam response.cookie w jakikolwiek sposób dyrektywa outputcache jest zepsuta. To nie jest udokumentowane w żaden sposób w .net. w rzeczywistości jest taki artykuł, który mówi: pamiętaj, że jeśli przechowujesz w pamięci podręcznej stronę z ciasteczkami, to pliki cookie są również buforowane. Doskonale zdaję sobie sprawę, że plik cookie jest częścią nagłówków HTTP, więc zostanie zapisany w pamięci podręcznej. moje pytanie brzmi, czy istnieje ustawienie w iis/web.config etc, które to umożliwia. Działa poprawnie po uruchomieniu w cassini –

+0

@Symeon to nie jest logiczne (buggy), co próbujesz zrobić. Ustawiłeś plik cookie dla jednego użytkownika, a co z następnym użytkownikiem, który nie ma zestawu plików cookie? Plik cookie ustawiony na kliencie - wymieszałeś pamięć podręczną klienta z pamięcią podręczną serwera. Pliki cookie są również przechowywane w pamięci podręcznej, gdy są po stronie klienta, a nie na serwerze. – Aristos

+1

Ktokolwiek odwiedza stronę, otrzyma plik cookie, niezależnie od tego, czy istnieje, czy nie. Plik cookie to tylko tekst w nagłówku http. Rozumiem, dlaczego może to być mylące, ale pomyślałem, że musiała być jakaś konfiguracja, ponieważ nie ma tam miejsca, w którym wzajemnie się wykluczają i działa dobrze w cassini.spójrz na to -http: //support.microsoft.com/kb/917072 brzmi jak to powinno POWINIEN buforować z ciasteczka, ponieważ dają obejście, aby to zatrzymać. –

0

Miałem ten sam problem i przetestowałem scenariusz podany przez Aristosa, ustawiając Location = "ServerAndClient" i to działa. Jeśli używam tylko Location = "Server", to nie zadziałało.

+0

W twoim przypadku działa tylko klient (buforowanie nagłówka odpowiedzi HTTP). Dane wyjściowe strony nie będą buforowane na serwerze, jeśli w odpowiedzi ustawisz pliki cookie. – d4n3

1

Sprawdź, czy używasz .NET 2.0 SP1 i czy zastosowałeś MS11-100 (wydany w grudniu 2012).

Mieliśmy do czynienia z podobnymi problemami, a skończyło się na skontaktowaniu się z pomocą techniczną firmy Microsoft. Potwierdzili, że MS11-100 łamie buforowanie wyjściowe, ale twierdził, że było to zgodne z projektem (ze względu na naturę luk w zabezpieczeniach ustalonych w łatce) i obecnie nie ma nic do zrobienia w celu przywrócenia funkcjonalności pamięci podręcznej wyników.

Prosty test: jeśli znajdziesz łatkę zainstalowaną, po prostu odinstaluj tę poprawkę i uruchom ponownie komputer. Powinieneś zobaczyć, że buforowanie wyjściowe zaczyna działać. Nie sądzę, aby ktokolwiek polecał to jako rozwiązanie produkcyjne ze względu na wpływ na bezpieczeństwo, więc używaj tego tylko jako sposobu na wyizolowanie problemu.

Zakończyliśmy testowanie nowszej wersji (trzeba przejść do wersji 4.0, 3.5 jest jedynie rozszerzeniem struktury 2.0, a nie samodzielną strukturą), a po rozwiązaniu wszystkich błędów kompilacji, buforowanie wyjściowe zaczęło działać natychmiast .

Pracowaliśmy również nad zmianą sposobu interakcji z plikami cookie, abyśmy mogli pozostać w ramach 2.0 (w końcu powinno być łatwiej przetestować nasze klasy obsługi plików cookie zamiast testowania całej całej aplikacji). Istnieje wiele przeszkód, a ostateczny produkt śmierdział "hackami", więc nie było wyjścia.

2

Jest to spowodowane różnymi wersjami platformy .NET. Zasadniczo niektóre wersje nigdy nie buforują strony z ustawionym plikiem cookie.

See this blog posting.

+0

Witamy w Stack Overflow! Dziękujemy za przesłanie odpowiedzi! Pamiętaj, aby uważnie przeczytać [FAQ na temat autopromocji] (http://stackoverflow.com/faq#promotion). Należy również pamiętać, że * wymagane * jest to, że publikujesz zrzeczenie się za każdym razem, gdy łączysz się z własną witryną/produktem. –

-1

Istnieje obejście, które mogą działać w niektórych scenariuszach: Jeśli plik cookie nie zależy w dużej mierze od kodu strony, ale może być obliczona z jakimś autonomicznym kodu, można ustawić cookie w Application_EndRequest Application_EndRequest są przetwarzane po OutputCache, a zatem pamięć podręczna jest przechowywana bez pliku cookie, ale następnie nagłówek pliku cookie jest dodawany przed wysłaniem żądania do klienta.

+0

Próbowałem tej metody i otrzymałem "nie można modyfikować nagłówków po błędzie odpowiedzi". – WiseGuyEh

2

Po przeprowadzeniu rzetelnych badań nad tym problemem, zrozumiałem i rozwiązałem problem.

Bufor wyjściowy powód nie grać ładny ciasteczek

Więc powód bufor wyjściowy nie będzie buforować odpowiedzi ciasteczek jest to, że cookies mogą być specyficzne dla użytkownika (np uwierzytelniania, analityczne śledzenia, itp.). Jeśli jeden lub więcej plików cookie z właściwością HttpCookie.Shareable = false, wówczas wyjściowa pamięć podręczna uznaje odpowiedź niekompatybilną.

Łącznie ciasteczka z pamięci podręcznej odpowiedzi

To gdzie to get trudne. Wyjściowa pamięć podręczna buforuje nagłówki odpowiedzi i zawartość razem i nie zapewnia żadnych haczyków do modyfikowania ich przed wysłaniem z powrotem do użytkownika. Jednak napisałem następujący dostawcy cache zwyczaj wyjście, aby zapewnić możliwość modyfikowania nagłówki pamięci podręcznej Response, zanim zostaną one odesłane do użytkownika (wymaga Fasterflect Nuget pakować):

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

Można by go podłączyć się tak:

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

A mógł używać go tak, aby wstawić ciasteczka:

HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache; 

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