2012-02-23 20 views
6

私のページにクッキーがある場合、出力キャッシュは機能しません!asp.net outputcacheとクッキー

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 

背後

例ページ

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

サンプルコードこれはキャッシュ、しかし、私はそれがない3つのResponse.Cookiesの行をコメントアウトしていない場合6または7のIISに展開。

VSで起動すると、うまく両方の方法で動作します。

iis/web.configなどで、response.cookiesを設定している間にoutputcacheを許可する設定がありますか。クッキーのコンテンツはキャッシュされるだけでなく、キャッシュされるhttpレスポンスの一部に過ぎないと理解しています。

ありがとう

シムオン。

+0

はあなたの前夜をしましたrは解決策を見つけましたか? – Allov

+1

私は同じことが真実であることを発見しましたが、公式の文書に遭遇していませんでした。明示的に動作しないことを明示する。 – JNappi

+0

@Allov、遅れて申し訳ありません - 私は解決策を持っていません。クッキーを取り除くことを除いて、またはクッキーが必要な場合は、クッキーを設定するページにスクリプトタグまたは0x0イメージを追加できます。 –

答えて

4

これをサーバー側でキャッシュしようとすると同時に、クライアントでCookieを設定しようとします。これは一緒には機能しません。

理由:サーバー側のキャッシュにページを設定すると、キャッシュされたバージョンが提供されたとき(クライアントに送信)、コードビハインドは実行されません。これがサーバー上のキャッシュポイントです。何も実行せずにキャッシュからそれを与える。

多分、ヘッダーにキャッシュを設定し、サーバー上の全ページをキャッシュしないでください。

+1

私は、クッキーを持つasp.netのページを作成しています。私はこのページをキャッシュし、コードを実行しないようにしたい。私はこれを行うために標準の.netコードを使用しています。しかし、私はresponse.cookieをoutputcacheディレクティブが壊れてしまったように見えます。これは、.net内のどのような方法でも記述されていません。実際には、クッキーでページをキャッシュしてもクッキーがキャッシュされているかどうかを覚えている記事があります。私は、cookieがhttpヘッダーの一部であることをよく知っているので、キャッシュされます。私の質問は、これを可能にするiis/web.configなどの設定がある場合です。これは、cassiniで実行すると大丈夫です –

+0

@Symeonこれは論理的ではありません。クッキーを1人のユーザーに設定すると、クッキーが設定されていない次のユーザーはどうなりますか?クライアント上に設定されたcookie - クライアントキャッシュとサーバーキャッシュが混在しています。クッキーは、サーバー上にないクライアント側のキャッシュにも保持されます。 – Aristos

+1

ページにアクセスする人は、存在するかどうかにかかわらずクッキーが与えられます。 Cookieはhttpヘッダーのテキストに過ぎません。私はなぜそれが混乱するかもしれないかを見ることができますが、私はちょうどそれが相互排他的であることをどこにしていないとして構成されている必要があると思った、それはcassiniでうまく動作します。これを見てください:http://support.microsoft.com/kb/917072これは、クッキーを使用してキャッシュしてください。 –

0

私は同じ問題を抱えていて、AristosのシナリオをLocation = "ServerAndClient"に設定してテストしました。私がLocation = "Server"だけを使用すると、うまく動作しませんでした。

+0

あなたのケースでは、クライアント(HTTP応答ヘッダーキャッシング)だけが動作します。あなたの応答でクッキーを設定すると、ページ出力はサーバー上にキャッシュされません。 – d4n3

1

.NET 2.0 SP1を実行しているか、MS11-100(2012年12月リリース)を適用しているかどうかを確認してください。

同様の問題が発生し、マイクロソフトサポートに連絡しました。彼らは出力キャッシュをMS11-100で中断したことを確認しましたが、(パッチで修正されたセキュリティ脆弱性のために)設計上のものであると主張し、出力キャッシュ機能を復元するために現在何も行われていません。

簡単なテスト:パッチがインストールされていることがわかったら、そのパッチをアンインストールして再起動するだけです。出力キャッシュが機能し始めていることがわかります。私は、誰もこれを生産上の解決策としてセキュリティ上の意味から推薦するとは思わないので、問題を分離するための手段としてのみ使用してください。

新しいフレームワークのテストが終了しました(4.0に移動する必要があります3.5は2.0フレームワークの拡張であり、スタンドアロンフレームワークではありません)。すべてのコンパイルエラーを解決した後、 。

私たちはまた、2.0フレームワークに留まることができるように、クッキーと対話する方法を変更しました。結局、アプリケーション全体をテストするのではなく、クッキーハンドラクラスをテストする方が簡単になるはずです。多くのハードルがあり、最終的な製品は「ハッキング」を再確認したので、これは無駄なものでした。

2

これは、.NET Frameworkのさまざまなバージョンによって発生します。基本的に、一部のバージョンではCookieセットを含むページをキャッシュしません。

See this blog posting

+0

ようこそスタックオーバーフロー!あなたの答えを投稿してくれてありがとう! [自己プロモーションに関するよくある質問](http://stackoverflow.com/faq#promotion)をよく読んでください。また、自分のサイト/製品にリンクするたびに免責条項を掲示することが必須*であることにも注意してください。 –

-1

いくつかのシナリオで働くかもしれない回避策があります: クッキーはページコードに大きく依存していないが、いくつかのスタンドアロンコードを用いて計算することができるならば、あなたはApplication_EndRequest Application_EndRequestにクッキーを設定することができますが後に処理されますOutputCache、したがってキャッシュはクッキーなしで格納されますが、要求がクライアントに配信される前に設定されたクッキーヘッダーが追加されます。

+0

このメソッドを試して、 "応答が送信された後にエラーを出力できません"というメッセージが表示されました。 – WiseGuyEh

2

この問題についてかなりの研究をした後、私はこの問題を理解し、回避するようになりました。

出力キャッシュは、だから、出力キャッシュは、クッキーと応答をキャッシュしません理由は、クッキーがユーザー固有の(例えば認証、分析、追跡、ことができることであるクッキー

で素晴らしいプレーしない理由等。)。プロパティーがHttpCookie.Shareable = falseの1つ以上のクッキーがある場合、出力キャッシュは応答をキャッシュ不可能と見なします。キャッシュされた応答

それはのトリッキーを取得する場所ですとCookieを含む

。出力キャッシュはレスポンスヘッダーとコンテンツを一緒にキャッシュし、それらをユーザーに返す前に変更するフックを提供しません。 はしかし、私は(がFasterflect nugetパッケージが必要です)彼らは戻って、ユーザに送信される前に、キャッシュされたレスポンスのヘッダを変更する機能を提供するために、次のカスタム出力キャッシュプロバイダーを書いた:

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

あなたはそれを配線します

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

やクッキーを挿入するには、このようにそれを使用することができます:このようなアップ

HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache; 

HeaderModOutputCacheProvider.RequestServedFromCache += (sender, e) => 
{ 
    e.AddCookies(new HttpCookieCollection 
    { 
     new HttpCookie("key", "value") 
    }); 
}; 
関連する問題