Öznitelik kullanan belirli eylemler için ASP.NET MVC'de Önbelleğe Alma İşlemini Önleme


197

Bir ASP.NET MVC 3 uygulamam var. Bu uygulama, jQuery aracılığıyla kayıtları ister. jQuery, sonuçları JSON biçiminde döndüren bir denetleyici eylemini geri çağırır. Bunu kanıtlayamadım, ancak verilerimin önbelleğe alınmasından endişe ediyorum.

Önbelleğin yalnızca belirli eylemlere uygulanmasını istiyorum, tüm eylemler için değil.

Verilerin önbelleğe alınmamasını sağlamak için bir eylemde bulunabileceğim bir özellik var mı? Değilse, tarayıcının önbelleğe alınmış bir küme yerine her seferinde yeni bir kayıt kümesi almasını nasıl sağlayabilirim?


1
Bir şeyin önbelleğe alındığını tahmin ediyorsanız, burada önbellek kontrol mekanizmalarını okumanızı öneririz: w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9

Yanıtlar:


304

JQuery'nin sonuçları önbelleğe almadığından emin olmak için ajax yöntemlerinize aşağıdakileri koyun:

$.ajax({
    cache: false
    //rest of your ajax setup
});

Veya MVC'de önbelleğe almayı önlemek için kendi özelliğimizi oluşturduk, aynısını yapabilirsiniz. İşte kodumuz:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NoCacheAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
        filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
        filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
        filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        filterContext.HttpContext.Response.Cache.SetNoStore();

        base.OnResultExecuting(filterContext);
    }
}

Sonra sadece kontrol cihazınızı süsleyin [NoCache]. VEYA bunu herkes için yapmak için, sadece burada olduğu gibi denetleyicilerinizi devralınan temel sınıfın sınıfına koyabilirsiniz (eğer varsa):

[NoCache]
public class ControllerBase : Controller, IControllerBase

Ayrıca, denetleyicinin tamamını süslemek yerine önbelleğe alınamayacakları durumlarda bazı eylemleri bu özellik ile dekore edebilirsiniz.

Sınıfınız veya işleminiz NoCachetarayıcınızda oluşturulduğunda gerçekleşmediyse ve çalışıp çalışmadığını kontrol etmek istiyorsanız, değişiklikleri derledikten sonra tarayıcınızda "sert yenileme" (Ctrl + F5) yapmanız gerektiğini unutmayın. Bunu yapana kadar tarayıcınız eski önbelleğe alınmış sürümü koruyacak ve "normal yenileme" (F5) ile yenilemeyecektir.


1
Yukarıdaki çözümdeki her şeyi denedim ve benim için çalışmıyor.
Obi Wan

9
Bu benim anlayış (ve ben jQuery uzmanı değilim) önbellek: false sadece sorgu dizesine jQuery tack "istek" başka bir şey için olduğunu düşünmek içine tarayıcı kandırmak için değişen bir değer yapar. Teoride, bu, tarayıcının hala sonuçları önbelleğe alacağı, yalnızca önbelleğe alınan sonuçları kullanmayacağı anlamına gelir. Yanıt üstbilgileri aracılığıyla önbelleğe almayı devre dışı bırakmak için istemcide daha verimli olmalıdır.
Josh

2
Eylem düzeyinde değil, yalnızca denetleyici düzeyinde çalışıldı.
Ramesh

3
Resmi ASP.NET paketinde böyle bir özniteliği dahil etmek istiyorum.
usr-local-ΕΨΗΕΛΩΝ

1
@ Frédéric, belirttiğiniz özellik bölümü, önbelleklerin depolanmamış içeriği önbelleğe alamayacağını söylüyor: "Depo yok" yanıt yönergesi, önbelleğin hemen istek veya yanıtın herhangi bir bölümünü saklamaması gerektiğini gösterir.
kristianp

258

Önbelleğe almayı önlemek için yerleşik önbellek özniteliğini kullanabilirsiniz.

.Net Framework için: [OutputCache(NoStore = true, Duration = 0)]

.Net Core için: [ResponseCache(NoStore = true, Duration = 0)]

Tarayıcıyı önbelleği devre dışı bırakmaya zorlamanın imkansız olduğunu unutmayın. Yapabileceğiniz en iyi şey, çoğu tarayıcının genellikle üstbilgi veya meta etiket biçiminde onurlandıracağı öneriler sunmaktır. Bu dekoratör nitelik sunucu önbelleğe alma devre dışı bırakmak ve aynı zamanda bu başlığı ekleyecektir: Cache-Control: public, no-store, max-age=0. Meta etiket eklemez. İstenirse, bunlar görünümde manuel olarak eklenebilir.

Ayrıca, JQuery ve diğer istemci çerçeveleri, URL'ye zaman damgası veya GUID gibi bir şeyler ekleyerek tarayıcının kaynağın önbelleğe alınmış sürümünü kullanmamasını sağlamaya çalışır. Bu, tarayıcının kaynağı tekrar istemesini sağlamada etkilidir, ancak önbelleğe almayı gerçekten engellemez.

Son bir not. Kaynakların sunucu ve istemci arasında da önbelleğe alınabileceğini bilmelisiniz. İSS'ler, proxy'ler ve diğer ağ aygıtları da kaynakları önbelleğe alır ve gerçek kaynağa bakmadan genellikle iç kuralları kullanırlar. Bunlar hakkında yapabileceğiniz pek bir şey yok. İyi haber şu ki, genellikle saniye veya dakika gibi daha kısa zaman dilimleri için önbellekleme yapıyorlar.


3
Bunun soruyu tam olarak çözmediğine inanıyorum. Bu, ASP.NET önbelleğe almayı devre dışı bırakır, ancak tarayıcı önbelleğe almayı devre dışı bırakmaz.
Rosdi Kasım

22
Tarayıcıyı önbelleğe almayı devre dışı bırakmaya zorlamak imkansızdır. Yapabileceğiniz en iyi şey, çoğu tarayıcının genellikle üstbilgi veya meta etiket biçiminde onurlandıracağı öneriler sunmaktır. Bu dekoratör özniteliği .NET sunucusu önbelleğini devre dışı bırakır ve üstbilgiyi de ekler Cache-Control:public, no-store, max-age=0. Meta etiket eklemez. İstenirse, bunlar görünümde manuel olarak eklenebilir.
Jaguir

1
Neden kullanacağınızı NoStore = trueve Duration = 0(başarıyla kullandım, teşekkürler) anlayabiliyorum , ancak VaryByParam = "None"parametre ne olursa olsun diğer iki seçenek tüm istekleri etkilediğinden hangi ek etki olurdu ?
Gone Kodlama

Ben MVC gerekli olduğunu sanmıyorum, ben sadece açık olduğunu. ASP.NET web formlarında ve kullanıcı denetimlerinde, bu öznitelik veya VaryByControl özniteliğinin gerekli olduğunu hatırlıyorum.
Jaguir

1
ASP.NET Core kullanımı için: '[ResponseCache (NoStore = true, Duration = 0)]'
Jeff

48

Tum ihtiyacin olan sey:

[OutputCache(Duration=0)]
public JsonResult MyAction(

veya tüm Denetleyici için devre dışı bırakmak istiyorsanız:

[OutputCache(Duration=0)]
public class MyController

Buradaki yorumlardaki tartışmaya rağmen, bu, tarayıcı önbelleğini devre dışı bırakmak için yeterlidir - bu ASP.Net'in tarayıcıya belgenin derhal sona erdiğini bildiren yanıt başlıkları yayınlamasına neden olur:

OutputCache Süresi = 0 Yanıt Başlıkları: max-age = 0, s-maxage = 0


6
IE8, bir Denetleyici Eyleminde yalnızca Süre = 0 kullanılarak geri düğmesi tıklatıldığında sayfanın önbelleğe alınmış sürümünü yine de oluşturur. Süre = 0 ile birlikte NoStore = true kullanmak (bkz. Jared'in cevabı) benim durumumdaki davranışı düzeltti.
Keith Ketterer

3
Bu ayarın biraz meraklı davranışa sahip Cache-Controlüzerepublic
ta.speot.is

max-age=0hiçbir zaman 'önbellek devre dışı' anlamına gelmez. Bu, yalnızca yanıt içeriğinin hemen eski olarak kabul edileceği anlamına gelir , ancak önbelleğin önbelleğe almasına izin verilir. Tarayıcılar, kullanmadan önce önbelleğe alınmış eski içeriğin tazeliğini doğrulamalıdır, ancak ek yönerge must-revalidatebelirtilmedikçe zorunlu değildir .
Frédéric

14

Denetleyici eyleminde başlığa aşağıdaki satırları ekleyin

    public ActionResult Create(string PositionID)
    {
        Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
        Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
        Response.AppendHeader("Expires", "0"); // Proxies.

5

İşte NoCacheChris Moschini cevabı gelen bilgileri kullanarak basitleştirilmiş mattytommo önerdiği özellik:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NoCacheAttribute : OutputCacheAttribute
{
    public NoCacheAttribute()
    {
        this.Duration = 0;
    }
}

Herhangi bir nedenle MVC 3, süreyi 0 olarak ayarlamanıza izin vermez. Bu ek açıklamaları eklemeniz gerekir ... geçici çözüm için teşekkürler!
micahhoover

max-age=0hiçbir zaman 'önbellek devre dışı' anlamına gelmez. Bu, yalnızca yanıt içeriğinin hemen eski olarak kabul edileceği anlamına gelir , ancak önbelleğin önbelleğe almasına izin verilir. Tarayıcılar, kullanmadan önce önbelleğe alınmış eski içeriğin tazeliğini doğrulamalıdır, ancak ek yönerge must-revalidatebelirtilmedikçe zorunlu değildir .
Frédéric

Tamlık için, minimal ve daha uygun yönerge, no-cacheönbelleğe almayı sağlayan ancak herhangi bir kullanımdan önce kaynak sunucuda yeniden doğrulama yetkisi veren yönetmeliktir . Yeniden doğrulanmış önbelleğe almayı bile önlemek için no-storebirlikte eklemeniz gerekir no-cache. ( no-storegeçici olarak yanlıştır çünkü uçucu önbelleklerin işaretli içeriği önbelleğe almasına izin verilir no-store.)
Frédéric

4

MVC6 ( DNX ) için,System.Web.OutputCacheAttribute

Not: NoStoreSüre parametresini ayarladığınızda dikkate alınmaz. İlk kayıt için bir başlangıç ​​süresi ayarlamak ve bunu özel özniteliklerle geçersiz kılmak mümkündür.

Ama bizde Microsoft.AspNet.Mvc.Filters.ResponseCacheFilter

 public void ConfigureServices(IServiceCollection services)
        ...
        services.AddMvc(config=>
        {
            config.Filters.Add(
                 new ResponseCacheFilter(
                    new CacheProfile() { 
                      NoStore=true
                     }));
        }
        ...
       )

İlk filtreyi özel bir özellikle geçersiz kılmak mümkündür

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public sealed class NoCacheAttribute : ActionFilterAttribute
    {
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            var filter=filterContext.Filters.Where(t => t.GetType() == typeof(ResponseCacheFilter)).FirstOrDefault();
            if (filter != null)
            {
                ResponseCacheFilter f = (ResponseCacheFilter)filter;
                f.NoStore = true;
                //f.Duration = 0;
            }

            base.OnResultExecuting(filterContext);
        }
    }

İşte bir kullanım örneği

    [NoCache]
    [HttpGet]
    public JsonResult Get()
    {            
        return Json(new DateTime());
    }

1

MVC'de Çıktı Önbellekleme

[OutputCache (NoStore = true, Süre = 0, Konum = "Yok", VaryByParam = "*")]

VEYA
[OutputCache (NoStore = true, Süre = 0, VaryByParam = "Yok")]


Bunu kullanmayı öneren çok sayıda cevap hakkındaki diğer yorumlara ( 1 , 2 , 3 ) bakın. İkinci satırınız yanlış ve bazı tarayıcılarda sorunlara yol açacak.
Frédéric


0

ASP.NET MVC 5 çözümleri:

  1. Merkezi bir konumda önlenmesi kodu önbelleğe alma: App_Start/FilterConfig.csbireyin RegisterGlobalFiltersyöntem:
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            // ...
            filters.Add(new OutputCacheAttribute
            {
                NoStore = true,
                Duration = 0,
                VaryByParam = "*",
                Location = System.Web.UI.OutputCacheLocation.None
            });
        }
    }
  1. Bunu yerine getirdikten sonra, benim anlayışım, farklı bir OutputCacheyönerge Controllerveya Viewdüzeyde uygulayarak genel filtreyi geçersiz kılabileceğinizdir . Düzenli Kontrolör için
[OutputCache(NoStore = true, Duration = 0, Location=System.Web.UI.ResponseCacheLocation.None, VaryByParam = "*")]

bir eğer yoksa ApiControllero olurdu

[System.Web.Mvc.OutputCache(NoStore = true, Duration = 0, Location = System.Web.UI.OutputCacheLocation.None, VaryByParam = "*")]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.