2017-08-31 49 views
7

Bir cookie değerine göre OutputCache değerini ayarlamak için bir yol var mı? kolaylıklar uğrunaOutputCache VaryByCustom tanımlama bilgisi değeri

, bu benim yöntemdir

[OutputCache(Duration = 600, VaryByParam = "None", VaryByCustom = "ztest")] 
public ViewResult Index() 
{ 
    return View(); 
} 
Benim Global.asax olan bu (benim tarayıcı sahip olduğunu doğrulayabilir

public override string GetVaryByCustomString(HttpContext context, string custom) 
{ 
    if (custom == "ztest") 
    { 
     HttpCookie ztest = context.Request.Cookies["ztest"]; 
     if (ztest != null) 
     { 
      return ztest.Value; 
     } 
    } 

    return base.GetVaryByCustomString(context, custom); 
} 

GetVaryByCustomString yöntemini geçersiz kılmak amacıyla ztest tanımlama bilgisi, ancak Index yöntemini hata ayıkladığımda, kesme noktasını her seferinde vurdum (bu, önbellek çalışmadığı anlamına gelir)

HttpResponse hiçbir giden çerez, bu nedenle bu nokta uygulamak olmaz: https://msdn.microsoft.com/en-us/library/system.web.httpcookie.shareable(v=vs.110).aspx

Bir Paylaþýlabilir (varsayılan değer) false olarak ayarlanır ile HttpResponse bir veya daha fazla giden çerezleri içeren verilen çıkış önbelleğe alma olacak yanıt için bastırıldı. Bu, olası hassas bilgileri içeren tanımlamaların yanıtta önbelleğe alınmasını ve birden çok istemciye gönderilmesini engeller. Çerezleri içeren bir yanıtın önbelleğe alınmasına izin vermek için, OutputCache yönergesi veya MVC'nin [OutputCache] özniteliği gibi yanıt için normal olarak önbelleğe almayı yapılandırın ve tüm giden çerezleri Shareable'ın true değerine ayarlanması için ayarlayın.

+0

'HttpCookie.Shareable = true' kontrol etmeyi denediniz mi? Sizin durumunuzda, çerez gibi olurdu.Paylaşılabilir = doğru; ' – Webruster

+0

" GetVaryByCustomString "yönteminde Shareable değerinin true olup olmadığını kontrol etmek mi istiyorsunuz? – Zac

+0

ilk olarak genellikle varsayılan olarak 'false', 'true' değiştirmeye çalışın' true ' – Webruster

cevap

4

İnce bir yanıt yoktur. aşağıdaki gibi

Açıklaması cevabı:

nedeni çıkış önbelleği çerezleri

güzel çalmıyor Yani çıkış önbelleği kurabiye bir yanıt önbelleğe olmayacak nedeni bir çerez olabilir o Kullanıcıya özel olmalı (örneğin kimlik doğrulama, analitik izleme, vb.). HttpCookie.Shareable = false numaralı bir veya daha fazla çerez varsa, çıktı önbelleği yanıtın iptal edilemez olduğunu düşünür.

Çözüm:

bazı geçici çözümler çıkış önbelleği birlikte yanıt başlıklarını ve içerik önbelleğe ve user.However geri göndermeden önce bu değiştirmek için herhangi kanca sağlamaz olsa vardır, yoktur kullanıcıya geri gönderilmeden önce önbelleğe alınan yanıtın üstbilgilerinden önce değişiklik yapma becerisinin bir yolu. Bunlardan biri, Fasterflect nuget paketini gerektirir.

kod örneği vardır:

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

Tel o kadar bu şekilde:

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

Ve bu şekilde kullanın:

HeaderModOutputCacheProvider.RequestServedFromCache += RequestServedFromCache; 

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

ben bilmiyorum soruya cevap verir, ama umarım doğru yöne işaret eder.

+0

Çözümünüzü kullanarak bitirmedim, ancak bunun yerine, cookie'lerin değerine bağlı olan koddan 'OutputCache' kaldırmayı bitirdim – Zac

İlgili konular