niedziela, 23 kwietnia 2017

Proste Cachowanie w .NET MVC


Umbraco ma w sobie system cachowania contentu. Co jednak, gdybyśmy chcieli pójść o krok dalej i zrobili cachowanie jeszcze wcześniej? Po co w ogóle się tym przejmować? O tym w dzisiejszym poście.

Sprawdźmy więc definicję. Czym właściwie jest Cache?

„Pamięć podręczna (ang. cache) – mechanizm, w którym część spośród danych zgromadzonych w źródłach o długim czasie dostępu i niższej przepustowości jest dodatkowo przechowywana w pamięci o lepszych parametrach. Ma to na celu poprawę szybkości dostępu do tych informacji, które przypuszczalnie będą potrzebne w najbliższej przyszłości.”

Źródło Wikipedia

W stronach takich jak WebDotNet, czy innych, w których content nie zmienia się dynamicznie, warto zastanowić się nad cachowaniem wyników, całych requestów.  Zdecydowałem się na zastosowanie „Donut Output Cache”, który jest inspirowany standardowym w MVC Output Cachem. Oto krótki poradnik jak możesz zastosować go w swoim projekcie MVC/Umbraco.
Instalujemy nuget package „MvcDonutCaching”. Cachowanie za pomocą tej biblioteki polega na zapisywaniu w pamięci całych zwrotów z metod Controllerów.  W aplikacji WebDotNet mam jak na razie dwa Controllery. Pierwszy odpowiedzialny za requesty o posty, a drugi o „normalne” strony z sekcjami. Aby dodać akcję do cachowania, należy dodać atrybut do metody. Przy zwykłym projekcie MVC możemy pokusić się o coś bardzo prostego jak np.:
    [DonutOutputCache(Duration = "300")]
Wartość zwracana zostanie w tym przypadku zapisana w pamięci na 300 sekund. Jeżeli w przeciągu tego czasu ktoś ponownie odpyta tę metodę, zwrócona zostanie wartość z pamięci, a kod z metody zostanie pominięty. W ten sposób możemy zaoszczędzić sporo czasu gdy np. nasza metoda odpytuje dodatkowo bazę danych i wykorzystuje jakiś algorytm do wyliczenia danych, które zwraca.
W moim przypadku musiałem pójść o krok dalej, jako że metoda Index jest wykonywana przy renderowaniu każdej strony na platformie. Musiałem więc wykorzystać dostosowany do moich potrzeb profil cachowania. Atrybut przy takim podejściu wygląda tak:
    [DonutOutputCache(CacheProfile = "Page.Cache")]
Profil jest zdefiniowany w Web.configu aplikacji:
    
      
        
          
        
      
    
Definiujemy tu nasz profil, czas przechowywania w pamięci oraz opcjonalną (a w moim przypadku wymaganą) dedykowaną klasę, która zajmie się kreacją kluczy do cacha. Zdecydowałem się, że kluczem dla moich elementów w pamięci będzie URL strony, gdyż jest to wartość unikalna.
    public class WebdotnetApplication : UmbracoApplication
    {
        public override string GetVaryByCustomString(HttpContext context, string custom)
        {
            if (custom.Equals("Page.Cache")) 
            {
                return context.Request.Url.AbsoluteUri;
            }
            return base.GetVaryByCustomString(context, custom);
        }
    }
Aby dedykowany kreator kluczy działał, musimy zrobić jeszcze jedną rzecz. Sprawić, by dziedziczył po naszej startowej klasie, która jest zdefiniowana w Global.asax. Przeciążyć metodę  „GetVaryByCustomString” i w pliku Global zmienić bieżącą klasę na naszą klasę dziedziczącą po poprzedniej, aby zachować ówczesną funkcjonalność. 
    <%@ Application Inherits="Webdotnet.Custom.Core.WebdotnetApplication" Language="C#" %>
To by było na tyle, jeżeli chodzi o dodawanie elementów. Używając Umbraco chcemy jednak, by przy wszelkich zmianach w contencie pamięć podręczna została wyczyszczona (a przynajmniej pozycja pod zmienianym kluczem została usunięta). Pozostało nam jeszcze podpięcie się pod Eventy umbraco. Aby to zrobić, należy stworzyć klasę, która dziedziczy po „ApplicationEventHandler” i nadpisać metodę „ApplicationStarted”. W ciele tej metody należy podpiąć się pod eventy zmiany/dodawania/usuwania itp. i dodać metody modyfikujące zawartość cacha, w moim przypadku usuwające jego zawartość.
    public class UmbracoEventHandler : ApplicationEventHandler
    {
        protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {
            ContentService.Published += UmbracoContentChangeHandler.OnPublished;
            ContentService.Created += UmbracoContentChangeHandler.OnCreated;
            ContentService.Saved += UmbracoContentChangeHandler.OnSaved;
            ContentService.Published += UmbracoContentChangeHandler.OnPublished;
            ContentService.UnPublished += UmbracoContentChangeHandler.OnUnpublished;
            ContentService.Moved += UmbracoContentChangeHandler.OnMoved;
            ContentService.Trashed += UmbracoContentChangeHandler.OnTrashed;
            ContentService.Deleted += UmbracoContentChangeHandler.OnDeleted;
        }
    }
W każdej z tych metod wywołuję usuwanie elementów z cacha, kod tej metody wygląda następująco:
    private static void RemoveItemsFromCache()
        {
            var cacheManager = new OutputCacheManager();
            cacheManager.RemoveItems();
        }

I to by było wszystko. W tym momencie będziemy już mieli działającego cacha wraz z usuwaniem jego elementów przy zmianach w contencie aplikacji.
To już wszystko na dziś, pozdrawiam Kamil.

Brak komentarzy:

Prześlij komentarz