Wyłącz pamięć podręczną przeglądarki dla całej witryny ASP.NET

199

Szukam metody wyłączenia pamięci podręcznej przeglądarki dla całej witryny ASP.NET MVC

Znalazłem następującą metodę:

Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
Response.Cache.SetNoStore();

A także metoda metatagów (dla mnie nie zadziała, ponieważ niektóre akcje MVC wysyłają częściowy HTML / JSON przez Ajax, bez nagłówka, metatag).

<meta http-equiv="PRAGMA" content="NO-CACHE">

Ale szukam prostej metody wyłączenia pamięci podręcznej przeglądarki dla całej witryny.

Palani
źródło

Odpowiedzi:

92
HttpContext.Current.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
HttpContext.Current.Response.Cache.SetValidUntilExpires(false);
HttpContext.Current.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.Cache.SetNoStore();

Wszystkie żądania są najpierw kierowane przez default.aspx - zakładając, że możesz po prostu wstawić kod.

Squiggs.
źródło
17
Umieściłbym go w Global.asax.cs w Application_BeginRequest (). Nie ufam tej domyślnej.aspx ... Kolejne pytanie: czy ma to pierwszeństwo przed atrybutami [OutputCache]?
chris166,
5
Podoba mi się pomysł stworzenia globalnego filtra akcji i umieszczenia tego w ten sposób. Neguje potrzebę martwienia się o Default.aspx i Global.asax.
Keith Adler
13
Umieszczenie tego w Application_BeingRequest może powodować pewne problemy. Jeśli twoje obrazy zostaną przekierowane przez środowisko uruchomieniowe .net (co może się zdarzyć, jeśli używasz mapowania symboli wieloznacznych dla ładnych adresów URL), żadne obrazy nie będą buforowane w przeglądarce. Może to NAPRAWDĘ spowolnić czas ładowania strony, ponieważ każde żądanie strony ponownie pobierze wszystkie obrazy.
herbrandson
4
Używanie czegokolwiek programowego zawsze zastępuje każdy zadeklarowany atrybut. Innymi słowy, użycie kodu OP zastąpi każdy zadeklarowany atrybut [OutputCache].
Dave Black
Czy są jakieś przemyślenia na temat testowania palenia i sprawdzenia, czy funkcja wyłączania pamięci podręcznej faktycznie działa?
paaone
366

Utwórz klasę, która dziedziczy z IActionFilter.

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

Następnie w razie potrzeby umieść atrybuty ...

[NoCache]
[HandleError]
public class AccountController : Controller
{
    [NoCache]
    [Authorize]
    public ActionResult ChangePassword()
    {
        return View();
    }
}
JKG
źródło
19
Zamiast HttpContext.Current.Response powinieneś prawdopodobnie użyć filterContext.HttpContext.Response, ponieważ HttpContext.Current zwraca obiekt HttpContext sprzed MVC, a filterContext.HttpContext zwraca post HVCpContextBase po MVC. Zwiększa testowalność i spójność.
mkedobbs,
5
IActionFilter jest już zaimplementowany w ActionFilterAttribute, więc nie trzeba go powtarzać.
Andrew Davey,
104
W aktualnych wersjach ASP.NET MVC można po prostu użyć OutputCacheAttribute, aby zapobiec buforowaniu: [OutputCache (NoStore = true, Duration = 0, VaryByParam = "None")]
Ashley Tate
9
Chciałbym zaznaczyć, że spędziłem kilka dni, używając każdego „wstawienia tego do kodu, aby przestać buforować” rozwiązania pod słońcem dla ASP.NET MVC, w tym zaakceptowanej odpowiedzi na to pytanie, bezskutecznie. Ta odpowiedź - atrybut - zadziałała. + 1 mln przedstawicieli, gdybym mógł ...
Tom Kidd
5
Możesz dodać if (filterContext.IsChildAction) return;u góry - zapobiegnie to, że akcja zewnętrzna nie będzie „buforowana”, jeśli wywoła akcję potomną, która jest ozdobiona NoCacheatrybutem. Innymi słowy, NoCacheatrybut nie wycieknie do innych akcji, jeśli wykonają akcje potomne. Ponadto nazwa klasy powinna być NoCacheAttributezgodna z ogólnie przyjętą konwencją nazewnictwa dla atrybutów.
Jakub Konecki
132

Zamiast tworzyć własne, po prostu użyj tego, co jest dla Ciebie.

Jak wspomniano wcześniej, nie wyłączaj buforowania dla wszystkiego. Na przykład skrypty jQuery często używane w ASP.NET MVC powinny być buforowane. Właściwie idealnie powinieneś używać CDN do tych celów, ale chodzi mi o to, że niektóre treści powinny być buforowane.

To, co według mnie działa najlepiej, zamiast posypywania wszędzie [OutputCache], to użycie klasy:

[System.Web.Mvc.OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public class NoCacheController  : Controller
{
}

Wszystkie kontrolery, które chcesz wyłączyć buforowanie, a następnie dziedziczą po tym kontrolerze.

Jeśli chcesz zastąpić wartości domyślne w klasie NoCacheController, po prostu określ ustawienia pamięci podręcznej dla metody akcji, a ustawienia metody akcji będą miały pierwszeństwo.

[HttpGet]
[OutputCache(NoStore = true, Duration = 60, VaryByParam = "*")]
public ViewResult Index()
{
  ...
}
Adam Tuliper - MSFT
źródło
4
@Ozziepeeps, twój komentarz jest nieprawidłowy. Dokumenty msdn omawiają buforowanie przeglądarki, a także prosty test pokażą, że ten atrybut zmienia nagłówek odpowiedzi kontroli pamięci podręcznej na „Kontrola pamięci podręcznej: public, no-store, max-age = 0” z „Kontrola pamięci podręcznej: prywatna” bez za pomocą atrybutu.
Adam Tuliper - MSFT,
2
także fyi - możesz kontrolować wszystkie trzy lokalizacje (serwer, proxy, klient) za pomocą tego atrybutu, więc absolutnie możesz kontrolować poza pamięć podręczną serwera. Dodatkowe informacje można znaleźć na stronie asp.net/mvc/tutorials/ ...
Adam Tuliper - MSFT
1
+1 „Jeśli chcesz zastąpić wartości domyślne w klasie NoCacheController, po prostu określ ustawienia pamięci podręcznej dla metody akcji, a ustawienia metody akcji będą miały pierwszeństwo.”
Korayem,
2
Pamiętaj, że jeśli używasz [System.Web.Mvc.OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]na poziomie klasy, nie możesz mieć częściowych widoków w swojej klasie.
Vivian River,
1
Metoda OutputCache nie zapobiegła buforowaniu IE, gdy były spełnione dwa warunki: 1) akcja nie przyjęła parametrów i 2) akcja zwróciła tylko tekst przez Content (someText). Gdy zwracam JSON i pobieram parametr, buforowanie IE zostaje poprawnie pokonane.
Kasey Speakman
10

Możesz wyłączyć buforowanie przeglądarki dla wszystkich stron renderowanych przez kontrolery (tj. Strony HTML), ale utrzymuj buforowanie w miejscu dla zasobów takich jak skrypty, arkusze stylów i obrazy . Jeśli używasz pakietowania i minimalizacji MVC4 +, będziesz chciał zachować domyślne czasy trwania pamięci podręcznej dla skryptów i arkuszy stylów (bardzo długi czas trwania, ponieważ pamięć podręczna zostaje unieważniona na podstawie zmiany unikalnego adresu URL, a nie na podstawie czasu).

W MVC4 +, aby wyłączyć buforowanie przeglądarki na wszystkich kontrolerach, ale zachować je dla wszystkiego, co nie jest obsługiwane przez kontroler, dodaj to do FilterConfig.RegisterGlobalFilters:

filters.Add(new DisableCache());

Zdefiniuj DisableCachew następujący sposób:

class DisableCache : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    }
}
Edward Brey
źródło
Niestety nie wydaje się to działać, ponieważ naciśnięcie przycisku Wstecz po wylogowaniu wyświetla stronę.
7 ʙᴀᴋᴇʀ
6

Wiem, że ta odpowiedź nie jest w 100% związana z pytaniem, ale może komuś pomóc.

Jeśli chcesz wyłączyć pamięć podręczną przeglądarki dla całej witryny ASP.NET MVC , ale chcesz to zrobić TYMCZASOWO, lepiej wyłączyć pamięć podręczną w przeglądarce.

Oto zrzut ekranu w Chrome

Carlos Martinez T.
źródło
Właśnie tego szukałem ... podczas tworzenia, jeśli zmienię plik .js, bardzo trudno jest to zrobić natychmiast, gdy mam problem z wykonaniem drobnych cykli rozwiązywania problemów / odświeżania / testowania. To jest idealne, dziękuję! Właśnie
ułatwiłem
2

Zaimplementowałem wszystkie poprzednie odpowiedzi i nadal miałem jeden widok, który nie działał poprawnie.

Okazało się, że nazwa widoku, z którym miałem problem, została nazwana „Najnowsze”. Najwyraźniej pomyliło to przeglądarkę Internet Explorer.

Po zmianie nazwy widoku (w kontrolerze) na inną nazwę (wybrałem opcję „Najnowsze5”) powyższe rozwiązania zaczęły działać.

DrHooverCraft
źródło
0

Możesz wypróbować poniższy kod w pliku Global.asax.

protected void Application_BeginRequest()
    {
        Response.Cache.SetCacheability(HttpCacheability.NoCache);
        Response.Cache.SetExpires(DateTime.UtcNow.AddHours(-1));
        Response.Cache.SetNoStore();
    }
NidhinSPradeep
źródło
-1

Interfejs użytkownika

<%@ OutPutCache Location="None"%>
<%
    Response.Buffer = true;
    Response.Expires = -1;
    Response.ExpiresAbsolute = System.DateTime.Now.AddSeconds(-1);
    Response.CacheControl = "no-cache";
%>

tło

Context.Response.Cache.SetCacheability(HttpCacheability.NoCache); 
Response.Expires = -1;          
Response.Cache.SetNoStore();
Alfa
źródło
1
potrzebuje prozy wyjaśniającej, nawet jeśli jest to technicznie poprawne
rmalayter