Udostępnij za pośrednictwem


Buforowanie danych przy uruchamianiu aplikacji (C#)

Autor : Scott Mitchell

Pobierz plik PDF

W dowolnej aplikacji internetowej niektóre dane będą często używane, a niektóre dane będą rzadko używane. Możemy poprawić wydajność naszej aplikacji ASP.NET, ładując z wyprzedzeniem często używane dane, technikę znaną jako buforowanie. W tym samouczku przedstawiono jedno podejście do ładowania danych z wyprzedzeniem, które polega na ładowaniu danych do cache podczas uruchamiania aplikacji.

Wprowadzenie

W dwóch poprzednich samouczkach przedstawiono buforowanie danych w warstwach prezentacji i buforowania. W buforowaniu danych za pomocą obiektu ObjectDataSource przyjrzeliśmy się używaniu funkcji buforowania objectDataSource do buforowania danych w warstwie prezentacji. Buforowanie danych w architekturze przeanalizował buforowanie w nowej, oddzielnej warstwie buforowania. Oba te samouczki korzystały z reaktywnego ładowania podczas pracy z pamięcią podręczną danych. Podczas ładowania reaktywnego za każdym razem, gdy dane są żądane, system najpierw sprawdza, czy znajduje się w pamięci podręcznej. Jeśli tak nie jest, pobiera dane ze źródła źródłowego, takiego jak baza danych, a następnie przechowuje je w pamięci podręcznej. Główną zaletą reaktywnego ładowania jest łatwość implementacji. Jedną z jego wad jest nierówna wydajność przy obsłudze żądań. Wyobraź sobie stronę, która używa warstwy buforowania z poprzedniego samouczka do wyświetlania informacji o produkcie. Gdy ta strona jest odwiedzana po raz pierwszy lub po usunięciu z pamięci podręcznej z powodu ograniczeń pamięci albo po osiągnięciu określonego czasu wygaśnięcia, dane muszą zostać pobrane z bazy danych. W związku z tym żądania tych użytkowników będą trwać dłużej niż żądania użytkowników, które mogą być obsługiwane przez pamięć podręczną.

Proaktywne ładowanie oferuje alternatywną strategię zarządzania pamięcią podręczną, która zapewnia równomierną wydajność pomiędzy żądaniami, poprzez ładowanie buforowanych danych zanim będą potrzebne. Zazwyczaj aktywne ładowanie korzysta z pewnego procesu, który okresowo sprawdza lub jest powiadamiany o aktualizacji danych bazowych. Następnie ten proces aktualizuje pamięć podręczną, aby zachować jej świeżość. Aktywne ładowanie jest szczególnie przydatne, jeśli bazowe dane pochodzą z powolnego połączenia z bazą danych, usługi sieci Web lub innego szczególnie powolnego źródła danych. Jednak takie podejście do proaktywnego ładowania jest trudniejsze do zaimplementowania, ponieważ wymaga tworzenia i wdrażania procesu w celu sprawdzania zmian i aktualizowania pamięci podręcznej.

Inną odmianą proaktywnego ładowania, którą będziemy omawiać w tym samouczku, jest ładowanie danych do pamięci podręcznej podczas uruchamiania aplikacji. Takie podejście jest szczególnie przydatne w przypadku buforowania danych statycznych, takich jak rekordy w tabelach odnośników bazy danych.

Uwaga / Notatka

Aby uzyskać bardziej szczegółowe informacje na temat różnic między aktywnym i reaktywnym ładowaniem, a także listami zalet, wad i zaleceń dotyczących implementacji, zapoznaj się z sekcją Zarządzanie zawartością pamięci podręcznejprzewodnika po architekturze buforowania dla aplikacji .NET Framework.

Krok 1. Określanie danych do buforowania podczas uruchamiania aplikacji

Przykłady buforowania przy wykorzystaniu reaktywnego ładowania, które omówiliśmy w dwóch poprzednich samouczkach, dobrze działają z danymi, które mogą okresowo się zmieniać i do wygenerowania nie wymagają nadmiernie dużo czasu. Jeśli jednak buforowane dane nigdy się nie zmieniają, przedawnienie stosowane przez ładowanie reaktywne jest zbędne. Podobnie, jeśli generowanie buforowanych danych zajmuje niezwykle dużo czasu, użytkownicy, których żądania trafią na pustą pamięć podręczną, będą musieli czekać przez długi czas, aż podstawowe dane zostaną pobrane. Rozważ buforowanie danych statycznych i danych, których wygenerowanie zajmuje wyjątkowo dużo czasu podczas uruchamiania aplikacji.

Chociaż bazy danych mają wiele dynamicznych, często zmieniających się wartości, większość ma również dość dużo danych statycznych. Na przykład praktycznie wszystkie modele danych mają co najmniej jedną kolumnę zawierającą określoną wartość z stałego zestawu wyborów. Patients Tabela bazy danych może zawierać kolumnęPrimaryLanguage, której zestaw wartości może być angielski, hiszpański, francuski, rosyjski, japoński itd. Często te typy kolumn są implementowane przy użyciu tabel odnośników. Zamiast przechowywać ciąg angielski lub francuski w Patients tabeli, tworzona jest druga tabela, która zawiera często dwie kolumny — unikatowy identyfikator i opis ciągu — z rekordem dla każdej możliwej wartości. Kolumna PrimaryLanguage w tabeli Patients przechowuje odpowiadający unikatowy identyfikator w tabeli pomocniczej. Na rysunku 1 język podstawowy pacjenta Johna Doe'a jest angielski, a Ed Johnson jest rosyjski.

Tabela Języków jest tabelą odwołań używaną przez tabelę Pacjentów

Rysunek 1.Languages Tabela jest tabelą odnośników używaną przez tabelę Patients

Interfejs użytkownika do edycji lub tworzenia nowego pacjenta zawiera listę rozwijaną dozwolonych języków wypełnionych rekordami w Languages tabeli. Bez buforowania za każdym razem, gdy ten interfejs jest odwiedzany, system musi wykonywać zapytania względem Languages tabeli. To marnotrawstwo i niepotrzebne, ponieważ wartości tabeli odnośników zmieniają się bardzo rzadko, jeśli w ogóle.

Możemy buforować dane Languages przy użyciu tych samych technik ładowania reaktywnego, które były omawiane w poprzednich samouczkach. Czasowe wygaśnięcie, stosowane w ładowaniu reaktywnym, nie jest jednak potrzebne dla danych statycznej tabeli wyszukiwania. Buforowanie przy użyciu ładowania reaktywnego byłoby lepsze niż w przypadku braku buforowania, ale najlepszym rozwiązaniem byłoby proaktywne ładowanie danych tabeli odnośników do pamięci podręcznej podczas uruchamiania aplikacji.

W tym samouczku dowiesz się, jak buforować dane tabeli odnośników i inne informacje statyczne.

Krok 2. Badanie różnych sposobów buforowania danych

Informacje mogą być programowo buforowane w aplikacji ASP.NET przy użyciu różnych metod. Widzieliśmy już, jak używać pamięci podręcznej danych w poprzednich samouczkach. Alternatywnie obiekty mogą być programowo buforowane przy użyciu statycznych elementów członkowskich lub stanu aplikacji.

Podczas pracy z klasą zazwyczaj należy utworzyć wystąpienie klasy przed uzyskaniem dostępu do jej członów. Aby na przykład wywołać metodę z jednej z klas w warstwie logiki biznesowej, musimy najpierw utworzyć wystąpienie klasy:

ProductsBLL productsAPI = new ProductsBLL();
productsAPI.SomeMethod();
productsAPI.SomeProperty = "Hello, World!";

Aby można było wywołać metodę SomeMethod lub pracować z elementem SomeProperty, musimy najpierw utworzyć wystąpienie klasy przy użyciu słowa kluczowego new . SomeMethod i SomeProperty są powiązane z konkretnym wystąpieniem. Czas życia tych członków jest powiązany z czasem życia skojarzonego obiektu. Statyczne elementy członkowskie, z drugiej strony, to zmienne, właściwości i metody, które są współużytkowane przez wszystkie wystąpienia klasy, a w związku z tym mają okres istnienia tak długo, jak klasa. Statyczne elementy członkowskie są oznaczane przez słowo kluczowe static.

Oprócz statycznych członków dane mogą być buforowane za pomocą stanu aplikacji. Każda aplikacja ASP.NET przechowuje kolekcję nazw/wartości współużytkowanych przez wszystkich użytkowników i strony aplikacji. Do tej kolekcji można uzyskać dostęp przy użyciu właściwości klasy HttpContext, a także używać jej w kodzie strony ASP.NET z klasy Application w następujący sposób:

Application["key"] = value;
object value = Application["key"];

Pamięć podręczna danych umożliwia dostęp do znacznie bogatszego interfejsu API do przechowywania danych, oferując mechanizmy wygasania na podstawie czasu i zależności, priorytety elementów pamięci podręcznej itd. W przypadku statycznych elementów członkowskich i stanu aplikacji takie funkcje muszą zostać ręcznie dodane przez dewelopera strony. Jednak w przypadku buforowania danych podczas uruchamiania aplikacji na całe jej życie, zalety pamięci podręcznej danych stają się nieistotne. W tym samouczku przyjrzymy się kodowi, który wykorzystuje wszystkie trzy techniki buforowania danych statycznych.

Krok 3. BuforowanieSuppliersdanych tabeli

Tabele bazy danych Northwind, które zaimplementowaliśmy do teraz, nie zawierają żadnych tradycyjnych tabel wyszukiwania. Cztery tabele DataTable zaimplementowane w naszej warstwie dostępu do danych (DAL) modelują tabele, których wartości są zmienne. Zamiast poświęcać czas na dodanie nowej tabeli DataTable do warstwy DAL, a następnie nowej klasy i metod do warstwy BLL, na potrzeby tego samouczka po prostu udajmy, że dane tabeli Suppliers są statyczne. W związku z tym możemy buforować te dane podczas uruchamiania aplikacji.

Aby rozpocząć, utwórz nową klasę o nazwie StaticCache.cs w folderze CL .

Tworzenie klasy StaticCache.cs w folderze CL

Rysunek 2. Tworzenie StaticCache.cs klasy w folderze CL

Musimy dodać metodę, która ładuje dane podczas uruchamiania do odpowiedniego magazynu pamięci podręcznej, a także metody zwracające dane z tej pamięci podręcznej.

[System.ComponentModel.DataObject]
public class StaticCache
{
    private static Northwind.SuppliersDataTable suppliers = null;
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using a static member variable
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        suppliers = suppliersBLL.GetSuppliers();
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return suppliers;
    }
}

Powyższy kod używa statycznej zmiennej składowej , suppliersdo przechowywania wyników z SuppliersBLL metody klasy GetSuppliers() , która jest wywoływana z LoadStaticCache() metody . Metoda LoadStaticCache() ma być wywoływana podczas uruchamiania aplikacji. Po załadowaniu tych danych podczas uruchamiania aplikacji każda strona, która musi współpracować z danymi dostawcy, może wywołać StaticCache metodę klasy GetSuppliers() . W związku z tym wywołanie bazy danych w celu pobrania dostawców odbywa się tylko raz na początku aplikacji.

Zamiast używać statycznej zmiennej składowej jako magazynu pamięci podręcznej, moglibyśmy też użyć stanu aplikacji lub pamięci podręcznej danych. Poniższy kod przedstawia klasę przebudowaną do używania stanu aplikacji.

[System.ComponentModel.DataObject]
public class StaticCache
{
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using application state
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        HttpContext.Current.Application["key"] = suppliersBLL.GetSuppliers();
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return HttpContext.Current.Application["key"] as Northwind.SuppliersDataTable;
    }
}

W LoadStaticCache()systemie przechowywane są informacje o dostawcy w zmiennej aplikacji klucz. Jest zwracany jako odpowiedni typ (Northwind.SuppliersDataTable) z GetSuppliers(). Podczas gdy dostęp do stanu aplikacji można uzyskać w klasach code-behind stron ASP.NET przy użyciu metody Application["key"], w architekturze musimy użyć metody HttpContext.Current.Application["key"], aby uzyskać bieżący HttpContext.

Podobnie pamięć podręczna danych może być używana jako magazyn, jak widać w poniższym kodzie:

[System.ComponentModel.DataObject]
public class StaticCache
{
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using the data cache
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        HttpRuntime.Cache.Insert(
          /* key */                "key", 
          /* value */              suppliers, 
          /* dependencies */       null, 
          /* absoluteExpiration */ Cache.NoAbsoluteExpiration, 
          /* slidingExpiration */  Cache.NoSlidingExpiration, 
          /* priority */           CacheItemPriority.NotRemovable, 
          /* onRemoveCallback */   null);
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return HttpRuntime.Cache["key"] as Northwind.SuppliersDataTable;
    }
}

Aby dodać element do pamięci podręcznej danych bez wygaśnięcia na podstawie czasu, jako parametry wejściowe użyj wartości System.Web.Caching.Cache.NoAbsoluteExpiration oraz System.Web.Caching.Cache.NoSlidingExpiration. Wybrano tę konkretną przeciążoną metodę pamięci podręcznej Insert danych, abyśmy mogli określić priorytet elementu pamięci podręcznej. Priorytet służy do określania elementów do usunięcia z pamięci podręcznej, gdy dostępna pamięć się kończy. W tym miejscu użyjemy priorytetu NotRemovable, co gwarantuje, że ten element pamięci podręcznej nie zostanie przeszycony.

Uwaga / Notatka

W tym samouczku implementacja klasy StaticCache wykorzystuje metodę zmiennej składowej statycznej. Kod technik stanu aplikacji i pamięci podręcznej danych jest dostępny w komentarzach w pliku klasy.

Krok 4. Wykonywanie kodu podczas uruchamiania aplikacji

Aby wykonać kod po pierwszym uruchomieniu aplikacji internetowej, musimy utworzyć specjalny plik o nazwie Global.asax. Ten plik może zawierać programy obsługi zdarzeń dla zdarzeń aplikacji, sesji i żądań. W tym miejscu można dodać kod, który będzie wykonywany za każdym razem, gdy aplikacja zostanie uruchomiona.

Global.asax Dodaj plik do katalogu głównego aplikacji internetowej, klikając prawym przyciskiem myszy nazwę projektu witryny internetowej w Eksploratorze rozwiązań programu Visual Studio i wybierając polecenie Dodaj nowy element. W oknie dialogowym Dodawanie nowego elementu wybierz typ elementu Global Application Class (Klasa aplikacji globalnej), a następnie kliknij przycisk Dodaj.

Uwaga / Notatka

Jeśli masz już plik Global.asax w projekcie, typ elementu Klasa aplikacji globalnej nie będzie wyświetlany w oknie dialogowym Dodawanie nowego elementu.

Dodaj plik Global.asax do katalogu głównego aplikacji internetowej

Rysunek 3. Dodawanie Global.asax pliku do katalogu głównego aplikacji internetowej (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Domyślny Global.asax szablon pliku zawiera pięć metod w tagu po stronie <script> serwera:

  • Application_Start jest wykonywany po pierwszym uruchomieniu aplikacji internetowej
  • Application_End jest uruchamiany, gdy aplikacja jest zamykana
  • Application_Error jest wykonywany za każdym razem, gdy nieobsługiwany wyjątek osiągnie aplikację
  • Session_Start wykonuje po utworzeniu nowej sesji
  • Session_End jest uruchamiany, gdy sesja wygasła lub porzucona

Procedura Application_Start obsługi zdarzeń jest wywoływana tylko raz podczas cyklu życia aplikacji. Aplikacja uruchamia się po raz pierwszy, gdy zasób ASP.NET jest żądany przez aplikację, i działa aż do jej ponownego uruchomienia, co może nastąpić z powodu modyfikacji zawartości folderu /Bin, modyfikacji Global.asax, zmiany zawartości folderu App_Code, lub modyfikacji pliku Web.config, między innymi. Zapoznaj się z przeglądem cyklu życia aplikacji ASP.NET, aby uzyskać bardziej szczegółową dyskusję na temat cyklu życia aplikacji.

W tych samouczkach tylko do metody Application_Start musimy dodać kod, więc możesz swobodnie usunąć pozostałe. W Application_Start po prostu wywołaj metodę klasy StaticCacheLoadStaticCache(), która załaduje i buforuje informacje o dostawcy:

<%@ Application Language="C#" %>
<script runat="server">
    void Application_Start(object sender, EventArgs e) 
    {
        StaticCache.LoadStaticCache();
    }
</script>

To wszystko! Podczas uruchamiania aplikacji metoda LoadStaticCache() będzie pobierać informacje o dostawcy z BLL i przechowywać je w statycznej zmiennej członkowskiej (lub w jakimkolwiek magazynie pamięci podręcznej, którego używasz w klasie StaticCache). Aby zweryfikować to zachowanie, ustaw punkt przerwania w metodzie Application_Start i uruchom aplikację. Należy pamiętać, że punkt przerwania jest osiągany po uruchomieniu aplikacji. Jednak kolejne żądania nie powodują wykonania metody Application_Start.

Użyj punktu przerwania, aby sprawdzić, czy program obsługi zdarzeń Application_Start jest wykonywany

Rysunek 4. Użyj punktu przerwania, aby sprawdzić, czy Application_Start procedura obsługi zdarzeń jest wykonywana (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Uwaga / Notatka

Jeśli nie osiągniesz Application_Start punktu przerwania podczas pierwszego rozpoczęcia debugowania, jest to spowodowane tym, że aplikacja została już uruchomiona. Wymuś ponowne uruchomienie aplikacji, modyfikując pliki Global.asax lub Web.config , a następnie spróbuj ponownie. Możesz po prostu dodać (lub usunąć) pusty wiersz na końcu jednego z tych plików, aby szybko ponownie uruchomić aplikację.

Krok 5. Wyświetlanie buforowanych danych

W tym momencie StaticCache klasa ma wersję danych dostawcy buforowanych podczas uruchamiania aplikacji, do których można uzyskać dostęp za pośrednictwem metody GetSuppliers() . Aby pracować z danymi z warstwy prezentacji, możemy użyć ObjectDataSource lub programowo wywołać metodę StaticCache klasy z klasy kod-behind strony ASP.NET GetSuppliers(). Przyjrzyjmy się użyciu kontrolek ObjectDataSource i GridView w celu wyświetlenia buforowanych informacji o dostawcy.

Rozpocznij od otwarcia strony AtApplicationStartup.aspx w folderze Caching. Przeciągnij kontrolkę GridView z przybornika do projektanta, ustawiając właściwość ID na Suppliers. Następnie z tagu inteligentnego GridView wybierz opcję utworzenia nowego obiektu ObjectDataSource o nazwie SuppliersCachedDataSource. Skonfiguruj obiekt ObjectDataSource, aby użyć StaticCache metody klasy GetSuppliers() .

Konfigurowanie obiektu ObjectDataSource do używania klasy StaticCache

Rysunek 5. Konfigurowanie obiektu ObjectDataSource do używania StaticCache klasy (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Użyj metody GetSuppliers(), aby pobrać buforowane dane dostawcy

Rysunek 6. Używanie GetSuppliers() metody do pobierania buforowanych danych dostawcy (kliknij, aby wyświetlić obraz o pełnym rozmiarze)

Po ukończeniu pracy kreatora program Visual Studio automatycznie doda pola BoundFields dla każdego pola danych w programie SuppliersDataTable. Znacznik deklaratywny GridView i ObjectDataSource powinien wyglądać podobnie do poniższego przykładu.

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="SupplierID" DataSourceID="SuppliersCachedDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CompanyName" HeaderText="CompanyName" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="Address" HeaderText="Address" 
            SortExpression="Address" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
        <asp:BoundField DataField="Phone" HeaderText="Phone" 
            SortExpression="Phone" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersCachedDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="StaticCache" />

Rysunek 7 przedstawia stronę po wyświetleniu za pośrednictwem przeglądarki. Dane wyjściowe są takie same, jak w przypadku pobrania danych z klasy BLL SuppliersBLL , ale użycie StaticCache klasy zwraca dane dostawcy, które są buforowane podczas uruchamiania aplikacji. Punkty przerwania można ustawić w metodzie StaticCache klasy GetSuppliers() , aby zweryfikować to zachowanie.

Buforowane dane dostawcy są wyświetlane w GridView

Rysunek 7: Buforowane dane dostawcy są wyświetlane w kontrolce GridView (Kliknij, aby wyświetlić obraz w pełnym rozmiarze)

Podsumowanie

Prawie każdy model danych zawiera sporo danych statycznych, zwykle implementowanych w postaci tabel wyszukiwania. Ponieważ te informacje są statyczne, nie ma powodu, aby stale uzyskiwać dostęp do bazy danych za każdym razem, gdy te informacje muszą być wyświetlane. Ponadto, ze względu na jego statyczny charakter, podczas buforowania danych nie jest konieczne określenie daty wygaśnięcia. W tym samouczku pokazano, jak pobrać takie dane i buforować je w pamięci podręcznej danych, stanie aplikacji i za pomocą statycznej zmiennej składowej. Te informacje są buforowane podczas uruchamiania aplikacji i pozostają w pamięci podręcznej przez cały okres istnienia aplikacji.

W tym samouczku i w poprzednich dwóch częściach zapoznaliśmy się z buforowaniem danych przez czas życia aplikacji, a także z używaniem terminów wygasających opartych na czasie. Jednak w przypadku buforowania danych bazy danych wygaśnięcie na podstawie czasu może być nie do końca idealne. Zamiast okresowo opróżniać pamięć podręczną, optymalne byłoby wykluczenie buforowanego elementu tylko wtedy, gdy bazowe dane bazy danych zostaną zmodyfikowane. Jest to idealne rozwiązanie, korzystając z zależności pamięci podręcznej SQL, które przeanalizujemy w następnym samouczku.

Szczęśliwe programowanie!

Informacje o autorze

Scott Mitchell, autor siedmiu książek ASP/ASP.NET i założyciel 4GuysFromRolla.com, współpracuje z technologiami internetowymi firmy Microsoft od 1998 roku. Scott pracuje jako niezależny konsultant, trener i pisarz. Jego najnowsza książka to Sams Teach Yourself ASP.NET 2.0 w ciągu 24 godzin. Można go uzyskać pod adresem mitchell@4GuysFromRolla.com.

Specjalne podziękowania

Ta seria samouczków została omówiona przez wielu przydatnych recenzentów. Główni recenzenci tego samouczka to Teresa Murphy i Zack Jones. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, napisz do mnie na adres mitchell@4GuysFromRolla.com.