Kilka wpisów wcześniej pisałem o atrybucie OutputCache. Dla prostych zastosowań sprawdza się dość dobrze, ale bardzo szybko można dostrzec jego ograniczenia i błędy. Przedstawmy najpierw kilka niedogodności związanych z OutputCache.
Załóżmy, że mamy kontroler z akcją ShowTime:
[OutputCache(Duration = 5*60)] public ActionResult ShowTime() { return View(); }
Widok zawiera po prostu aktualny czas:
@DateTime.Now.ToString()
Następnie, gdzieś na stronie renderujemy powyższą akcję:
@Html.Action("ShowTime")
Na razie wszystko działa tak jak chcemy – zawartość akcji jest buforowana co 5 minut. Problem polega na tym, że implementacja w MVC nie radzi sobie dobrze z buforowaniem akcji zagnieżdżonych (child actions), takimi jak ta powyższa. Na przykład, nie wspierane są profile zdefiniowane w web.config:
<outputCacheSettings> <outputCacheProfiles> <add name="CustomProfile" duration="20" varyByParam="*" /> </outputCacheProfiles> </outputCacheSettings> </caching>
Ustawienie atrybutu w następujący sposób po prostu nie zadziała:
[OutputCache(CacheProfile = "CustomProfile"] public ActionResult ShowTime() { return View(); }
Analogicznie zablokowanie buforowania w web.config działa wyłącznie dla akcji głównych a nie zagnieżdżonych:
<outputCache enableOutputCache="false"/>
Innym wyzwaniem z jakim spotkałem się to buforowanie całej strony z wyjątkiem pewnego fragmentu np. nazwy użytkownika. Dekorując OutputCache główną akcję, nie mamy możliwości usunięcia z buforowania jakichkolwiek akcji potomnych. Na szczęście możemy ściągnąć pakiet MvcDonutOutput , który rozwiązuje powyższe problemy:
Sposób użycia jest analogiczny do standardowego OutputCache:
[DonutOutputCache(CacheProfile = "CustomProfile")] public ActionResult ShowTime() { return View(); }
Do dyspozycji mamy te same parametry i oczywiście teraz profile zdefiniowane w web.config działają również dla akcji potomnych.
Biblioteka rozszerza również metodę Action o argument umożliwiający nam wyłączenie specyficznej akcji z buforowania:
public static MvcHtmlString Action(this HtmlHelper html, string actionName, string controllerName, RouteValueDictionary routeValues, bool excludeFromParentCache)
Przykład:
@Html.Action("LoginDetails", "Account", true)
Ustawienie flagi na true spowoduje, że akcja LoginDetails nie będzie buforowana. Częstym scenariuszem jest, że chcemy buforować całą główną akcję z wyjątkiem np. jednej pokazującej dane zmieniające się bardzo często.
Możliwe jest również programowe usunięcie poszczególnych składowych z bufora:
var cacheManager = new OutputCacheManager(); //usuwa akcje Index z kontrolera Home cacheManager.RemoveItem("Home", "Index"); // usuwa wszystkie pozycje cacheManager.RemoveItems();
Myślę, że warto zastąpić OutputCache atrybutem DonutOutputCache w swoich projektach. Wcześniej czy później, każdy spotka się ze wspomnianymi ograniczeniami.
Pomocne dzięki za informację … Dodaję bloga do RSS-ów 🙂