Cegah Caching di ASP.NET MVC untuk tindakan tertentu menggunakan atribut

196

Saya memiliki aplikasi ASP.NET MVC 3. Aplikasi ini meminta catatan melalui jQuery. jQuery memanggil kembali ke tindakan pengontrol yang mengembalikan hasil dalam format JSON. Saya belum dapat membuktikan ini, tetapi saya khawatir data saya mungkin akan di-cache.

Saya hanya ingin caching diterapkan pada tindakan tertentu, bukan untuk semua tindakan.

Apakah ada atribut yang bisa saya lakukan untuk memastikan bahwa data tidak di-cache? Jika tidak, bagaimana saya memastikan bahwa browser mendapat set rekaman baru setiap kali, bukannya set cache?

Pengembang JavaScript
sumber
1
Jika Anda menduga ada sesuatu yang sedang di-cache, maka saya sarankan Anda membaca tentang mekanisme kontrol cache di sini: w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9

Jawaban:

304

Untuk memastikan bahwa JQuery tidak melakukan caching hasilnya, pada metode ajax Anda, tuliskan yang berikut:

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

Atau untuk mencegah caching di MVC, kami membuat atribut kami sendiri, Anda bisa melakukan hal yang sama. Ini kode kami:

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

Kemudian hiasi saja pengontrol Anda dengan [NoCache]. ATAU untuk melakukannya untuk semua yang Anda bisa letakkan atribut pada kelas kelas dasar tempat Anda mewarisi pengontrol Anda (jika ada) seperti yang kami miliki di sini:

[NoCache]
public class ControllerBase : Controller, IControllerBase

Anda juga dapat menghias beberapa tindakan dengan atribut ini jika Anda membutuhkannya agar tidak dapat di-cache, alih-alih mendekorasi keseluruhan pengontrol.

Jika kelas atau tindakan Anda tidak memiliki NoCachesaat itu diberikan di browser Anda dan Anda ingin memeriksa itu berfungsi, ingat bahwa setelah mengkompilasi perubahan yang Anda butuhkan untuk melakukan "penyegaran keras" (Ctrl + F5) di browser Anda. Sampai Anda melakukannya, browser Anda akan menyimpan versi cache lama, dan tidak akan menyegarkan dengan "refresh normal" (F5).

mattytommo
sumber
1
Saya mencoba semuanya dalam solusi di atas dan itu tidak berhasil untuk saya.
Obi Wan
9
Ini pemahaman saya (dan saya bukan ahli jQuery) bahwa cache: false hanya membuat jQuery memaku pada string kueri nilai yang berubah untuk "mengelabui" browser agar mengira permintaan itu untuk sesuatu yang lain. Secara teori, ini berarti browser masih akan menyimpan hasil, tidak akan menggunakan hasil yang di-cache. Seharusnya lebih efisien pada klien untuk menonaktifkan caching melalui header respons.
Josh
2
Hanya bekerja pada level pengontrol dan bukan pada level aksi.
Ramesh
3
Saya akan menambahkan termasuk atribut seperti itu dalam paket ASP.NET resmi :-)
usr-local-ΕΨΗΕΛΩΝ
1
@ Frédéric, bagian dari spesifikasi yang Anda tunjuk mengatakan bahwa cache tidak dapat menembolok konten no-store: Arahan respons "no-store" menunjukkan bahwa cache TIDAK HARUS menyimpan bagian apa pun dari permintaan atau respons langsung.
kristianp
258

Anda dapat menggunakan atribut cache bawaan untuk mencegah caching.

Untuk .net Framework: [OutputCache(NoStore = true, Duration = 0)]

Untuk .net Core: [ResponseCache(NoStore = true, Duration = 0)]

Perlu diketahui bahwa tidak mungkin memaksa browser untuk menonaktifkan caching. Yang terbaik yang dapat Anda lakukan adalah memberikan saran yang sebagian besar browser akan hormati, biasanya dalam bentuk header atau meta tag. Atribut dekorator ini akan menonaktifkan caching server dan juga menambahkan header ini: Cache-Control: public, no-store, max-age=0. Itu tidak menambahkan tag meta. Jika diinginkan, itu dapat ditambahkan secara manual dalam tampilan.

Selain itu, JQuery dan kerangka kerja klien lainnya akan berupaya mengelabui browser agar tidak menggunakan versi sumber daya yang di-cache dengan menambahkan hal-hal ke url, seperti stempel waktu atau GUID. Ini efektif dalam membuat browser meminta sumber daya lagi tetapi tidak benar-benar mencegah caching.

Pada catatan akhir. Anda harus menyadari bahwa sumber daya juga dapat di-cache di antara server dan klien. ISP, proxy, dan perangkat jaringan lain juga menyimpan sumber daya dan mereka sering menggunakan aturan internal tanpa melihat sumber daya yang sebenarnya. Tidak banyak yang dapat Anda lakukan tentang ini. Berita baiknya adalah mereka biasanya melakukan cache untuk jangka waktu yang lebih pendek, seperti detik atau menit.

Jaguir
sumber
3
Saya percaya ini tidak sepenuhnya menjawab pertanyaan. Ini menonaktifkan caching ASP.NET tetapi tidak caching peramban.
Rosdi Kasim
22
Tidak mungkin memaksa browser untuk menonaktifkan caching. Yang terbaik yang dapat Anda lakukan adalah memberikan saran yang sebagian besar browser akan hormati, biasanya dalam bentuk header atau meta tag. Atribut dekorator ini akan menonaktifkan caching server .NET dan juga menambahkan header Cache-Control:public, no-store, max-age=0. Itu tidak menambahkan tag meta. Jika diinginkan, itu dapat ditambahkan secara manual dalam tampilan.
Jaguir
1
Saya dapat mengerti mengapa Anda akan menggunakan NoStore = truedan Duration = 0(yang telah saya gunakan dengan sukses, terima kasih), tetapi efek tambahan apa yang akan VaryByParam = "None"terjadi karena dua opsi lainnya memengaruhi semua permintaan terlepas dari parameter?
Lewat Coding
Saya tidak berpikir itu diperlukan dalam MVC, saya hanya bersikap eksplisit. Saya ingat bahwa dalam formulir web ASP.NET dan kontrol pengguna, diperlukan atribut ini atau atribut VaryByControl.
Jaguir
1
Untuk penggunaan ASP.NET Core: '[ResponseCache (NoStore = true, Durasi = 0)]'
Jeff
48

Yang kamu butuhkan adalah:

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

atau, jika Anda ingin menonaktifkannya untuk seluruh Pengontrol:

[OutputCache(Duration=0)]
public class MyController

Terlepas dari perdebatan dalam komentar di sini, ini cukup untuk menonaktifkan cache browser - ini menyebabkan ASP.Net memancarkan header respons yang memberi tahu browser dokumen segera kedaluwarsa:

Durasi OutputCache = 0 Header Respons: max-age = 0, s-maxage = 0

Chris Moschini
sumber
6
IE8 masih membuat versi halaman yang di-cache ketika tombol kembali diklik hanya menggunakan Durasi = 0 pada Aksi Controller. Menggunakan NoStore = true bersama dengan Durasi = 0 (lihat jawaban Jared) memperbaiki perilaku dalam kasus saya.
Keith Ketterer
3
Ini memiliki perilaku yang agak aneh dari pengaturan Cache-Controlkepublic
ta.speot.is
max-age=0tidak pernah berarti 'cache dinonaktifkan'. Ini hanya berarti bahwa konten respons harus dianggap segera basi , tetapi cache diizinkan untuk menyimpannya. Browser harus memvalidasi kesegaran konten basi yang di-cache sebelum menggunakannya, tetapi tidak wajib kecuali direktif tambahan must-revalidateditentukan.
Frédéric
14

Dalam aksi controller tambahkan ke header baris berikut

    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.
dfortun
sumber
5

Inilah NoCacheatribut yang dikemukakan oleh mattytommo, disederhanakan dengan menggunakan informasi dari jawaban Chris Moschini:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NoCacheAttribute : OutputCacheAttribute
{
    public NoCacheAttribute()
    {
        this.Duration = 0;
    }
}
Konamiman
sumber
Untuk beberapa alasan MVC 3 tidak hanya membiarkan Anda mengatur durasinya menjadi 0. Anda harus menambahkan anotasi ini ... terima kasih atas solusinya!
micahhoover
max-age=0tidak pernah berarti 'cache dinonaktifkan'. Ini hanya berarti bahwa konten respons harus dianggap segera basi , tetapi cache diizinkan untuk menyimpannya. Browser harus memvalidasi kesegaran konten basi yang di-cache sebelum menggunakannya, tetapi tidak wajib kecuali direktif tambahan must-revalidateditentukan.
Frédéric
Untuk kelengkapan, direktif minimal dan lebih tepat adalah no-cache, yang masih memungkinkan caching tetapi mandat untuk memvalidasi ulang di server asal sebelum digunakan. Untuk menghindari caching bahkan divalidasi ulang Anda harus menambahkan no-storebersama dengan no-cache. ( no-storesendirian jelas-jelas salah karena cache volatil diperbolehkan untuk men-cache konten yang ditandai sebagai no-store.)
Frédéric
4

Untuk MVC6 ( DNX ), tidak adaSystem.Web.OutputCacheAttribute

Catatan: ketika Anda mengatur NoStoreparameter Durasi tidak dipertimbangkan. Dimungkinkan untuk menetapkan durasi awal untuk pendaftaran pertama dan menimpanya dengan atribut khusus.

Tapi kami punya Microsoft.AspNet.Mvc.Filters.ResponseCacheFilter

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

Dimungkinkan untuk mengganti filter awal dengan atribut khusus

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

Berikut ini adalah use case

    [NoCache]
    [HttpGet]
    public JsonResult Get()
    {            
        return Json(new DateTime());
    }
Davut Gürbüz
sumber
1

Output Caching dalam MVC

[OutputCache (NoStore = true, Durasi = 0, Location = "None", VaryByParam = "*")]

ATAU
[OutputCache (NoStore = true, Durasi = 0, VaryByParam = "Tidak Ada")]

Deepak
sumber
Lihat komentar lain ( 1 , 2 , 3 ) pada sejumlah jawaban yang sudah menyarankan menggunakan ini. Baris kedua Anda salah dan akan menyebabkan masalah dengan beberapa browser.
Frédéric
1

Nilai atribut yang benar untuk Asp.Net MVC Core untuk mencegah caching browser (termasuk Internet Explorer 11 ) adalah:

[ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]

seperti yang dijelaskan dalam dokumentasi Microsoft:

Caching respons di ASP.NET Core - NoStore dan Location.None

Nenad
sumber
0

Solusi ASP.NET MVC 5:

  1. Caching kode pencegahan di lokasi pusat: yang App_Start/FilterConfig.cs's RegisterGlobalFiltersmetode:
    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. Setelah Anda memilikinya, pemahaman saya adalah bahwa Anda dapat mengganti filter global dengan menerapkan OutputCachearahan Controlleratau Viewlevel yang berbeda. Untuk Kontroler biasa itu
[OutputCache(NoStore = true, Duration = 0, Location=System.Web.UI.ResponseCacheLocation.None, VaryByParam = "*")]

atau jika itu adalah ApiControlleritu

[System.Web.Mvc.OutputCache(NoStore = true, Duration = 0, Location = System.Web.UI.OutputCacheLocation.None, VaryByParam = "*")]
Csaba Toth
sumber