Poprawa wydajności dzięki buforowaniu danych wyjściowych (VB)

autor: Microsoft

Z tego samouczka dowiesz się, jak znacznie poprawić wydajność aplikacji internetowych ASP.NET MVC, korzystając z buforowania danych wyjściowych. Dowiesz się, jak buforować wynik zwrócony z akcji kontrolera, dzięki czemu ta sama zawartość nie musi być tworzona za każdym razem, gdy nowy użytkownik wywołuje akcję.

Celem tego samouczka jest wyjaśnienie, jak znacznie poprawić wydajność aplikacji ASP.NET MVC, korzystając z pamięci podręcznej danych wyjściowych. Pamięć podręczna danych wyjściowych umożliwia buforowanie zawartości zwróconej przez akcję kontrolera. W ten sposób ta sama zawartość nie musi być generowana za każdym razem, gdy jest wywoływana ta sama akcja kontrolera.

Załóżmy na przykład, że aplikacja ASP.NET MVC wyświetla listę rekordów bazy danych w widoku o nazwie Index. Zwykle za każdym razem, gdy użytkownik wywołuje akcję kontrolera zwracającą widok Indeks, zestaw rekordów bazy danych należy pobrać z bazy danych, wykonując zapytanie bazy danych.

Jeśli z drugiej strony skorzystasz z pamięci podręcznej wyjściowej, możesz uniknąć wykonywania zapytania bazy danych za każdym razem, gdy każdy użytkownik wywołuje tę samą akcję kontrolera. Widok można pobrać z pamięci podręcznej zamiast ponownego generowania z akcji kontrolera. Buforowanie umożliwia uniknięcie wykonywania nadmiarowej pracy na serwerze.

Włączanie buforowania danych wyjściowych

Buforowanie danych wyjściowych można włączyć przez dodanie atrybutu <OutputCache> do pojedynczej akcji kontrolera lub całej klasy kontrolera. Na przykład kontroler w liście 1 uwidacznia akcję o nazwie Index(). Dane wyjściowe akcji Index() są buforowane przez 10 sekund.

Lista 1 — Controllers\HomeController.vb

<HandleError()> _
Public Class HomeController
    Inherits System.Web.Mvc.Controller

    <OutputCache(Duration:=10, VaryByParam:="none")> _
    Function Index()
        Return View()
    End Function

End Class

W wersjach beta ASP.NET MVC buforowanie danych wyjściowych nie działa dla adresu URL, takiego jak http://www.MySite.com/. Zamiast tego musisz wprowadzić adres URL, taki jak "http://www.MySite.com/Home/Index".

Na liście 1 dane wyjściowe akcji Index() są buforowane przez 10 sekund. Jeśli wolisz, możesz określić znacznie dłuższy czas trwania pamięci podręcznej. Jeśli na przykład chcesz buforować dane wyjściowe akcji kontrolera przez jeden dzień, możesz określić czas trwania pamięci podręcznej 86400 sekund (60 sekund * 60 minut * 24 godziny).

Nie ma gwarancji, że zawartość będzie buforowana przez określony czas. Gdy zasoby pamięci staną się niskie, pamięć podręczna automatycznie rozpoczyna eksmitowanie zawartości.

Kontroler główny na liście 1 zwraca widok Indeks w pozycji Lista 2. Nie ma nic specjalnego w tym widoku. Widok Indeks po prostu wyświetla bieżący czas (patrz Rysunek 1).

Lista 2 — Views\Home\Index.aspx

<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>
</head>
<body>
    <div>
    
    The current time is: <%= DateTime.Now.ToString("T") %>
    
    </div>
</body>
</html>

Rysunek 1 . Widok indeksu buforowanego

clip_image002

Jeśli wielokrotnie wywołujesz akcję Indeks(), wprowadzając adres URL /Home/Index na pasku adresu przeglądarki i naciskając przycisk Odśwież/Załaduj ponownie w przeglądarce wielokrotnie, czas wyświetlany przez widok Indeks nie zmieni się przez 10 sekund. Ten sam czas jest wyświetlany, ponieważ widok jest buforowany.

Ważne jest, aby zrozumieć, że ten sam widok jest buforowany dla wszystkich użytkowników odwiedzających aplikację. Każda osoba, która wywołuje akcję Index(), otrzyma tę samą buforowana wersję widoku indeksu. Oznacza to, że ilość pracy, którą serwer internetowy musi wykonać w celu obsługi widoku indeksu, jest znacznie zmniejszona.

Widok w liście 2 zdarza się robić coś naprawdę prostego. Widok wyświetla tylko bieżący czas. Można jednak równie łatwo buforować widok, który wyświetla zestaw rekordów bazy danych. W takim przypadku zestaw rekordów bazy danych nie musi być pobierany z bazy danych za każdym razem, gdy jest wywoływana akcja kontrolera zwracająca widok. Buforowanie może zmniejszyć ilość pracy, którą musi wykonać zarówno serwer internetowy, jak i serwer bazy danych.

Nie używaj strony <%@ OutputCache %> dyrektywy w widoku MVC. Ta dyrektywa krwawi z Web Forms świata i nie powinna być używana w ASP.NET aplikacji MVC.

Gdzie zawartość jest buforowana

Domyślnie, gdy używasz atrybutu <OutputCache> , zawartość jest buforowana w trzech lokalizacjach: serwer internetowy, wszystkie serwery proxy i przeglądarka internetowa. Możesz kontrolować dokładnie miejsce, w którym jest buforowana zawartość, modyfikując właściwość Location atrybutu <OutputCache> .

Właściwość Location można ustawić na dowolną z następujących wartości:

· Wszelki

· Klienta

· Dalszych

· Serwera

· Brak

· ServerAndClient

Domyślnie właściwość Location ma wartość Dowolna. Istnieją jednak sytuacje, w których można buforować tylko w przeglądarce lub tylko na serwerze. Jeśli na przykład buforujesz informacje, które są spersonalizowane dla każdego użytkownika, nie należy buforować informacji na serwerze. Jeśli wyświetlasz różne informacje dla różnych użytkowników, należy buforować informacje tylko na kliencie.

Na przykład kontroler w liście 3 uwidacznia akcję o nazwie GetName(), która zwraca bieżącą nazwę użytkownika. Jeśli Jack zaloguje się do witryny internetowej i wywoła akcję GetName(), akcja zwróci ciąg "Hi Jack". Jeśli następnie aplikacja Jill zaloguje się do witryny internetowej i wywoła akcję GetName(), otrzyma również ciąg "Hi Jack". Ciąg jest buforowany na serwerze internetowym dla wszystkich użytkowników po początkowym wywołaniu akcji kontrolera.

Lista 3 — Controllers\BadUserController.vb

Public Class BadUserController
    Inherits System.Web.Mvc.Controller

    <OutputCache(Duration:=3600, VaryByParam:="none")> _
    Function Index()
        Return "Hi " & User.Identity.Name
    End Function

End Class

Najprawdopodobniej kontroler w liście 3 nie działa tak, jak chcesz. Nie chcesz wyświetlać komunikatu "Hi Jack" do Jill.

Nigdy nie należy buforować spersonalizowanej zawartości w pamięci podręcznej serwera. Jednak w celu zwiększenia wydajności może być konieczne buforowanie spersonalizowanej zawartości w pamięci podręcznej przeglądarki. Jeśli buforujesz zawartość w przeglądarce, a użytkownik wywołuje tę samą akcję kontrolera wiele razy, zawartość można pobrać z pamięci podręcznej przeglądarki zamiast serwera.

Zmodyfikowany kontroler w pozycji Lista 4 buforuje dane wyjściowe akcji GetName(). Jednak zawartość jest buforowana tylko w przeglądarce, a nie na serwerze. W ten sposób, gdy wielu użytkowników wywołuje metodę GetName(), każda osoba otrzymuje własną nazwę użytkownika, a nie nazwę użytkownika innej osoby.

Lista 4 — Controllers\UserController.vb

Public Class UserController
    Inherits System.Web.Mvc.Controller

    <OutputCache(Duration:=3600, VaryByParam:="none", Location:=OutputCacheLocation.Client, NoStore:=True)> _
    Function GetName()
        Return "Hi " & User.Identity.Name
    End Function

End Class

Zwróć uwagę, że <atrybut OutputCache> w liście 4 zawiera właściwość Location ustawioną na wartość OutputCacheLocation.Client. Atrybut <OutputCache> zawiera również właściwość NoStore. Właściwość NoStore służy do informowania serwerów proxy i przeglądarek o tym, że nie powinny przechowywać trwałej kopii buforowanej zawartości.

Różnicowanie pamięci podręcznej danych wyjściowych

W niektórych sytuacjach może być potrzebne różne buforowane wersje tej samej zawartości. Załóżmy na przykład, że tworzysz stronę wzorcową/szczegółową. Na stronie wzorcowej jest wyświetlana lista tytułów filmów. Po kliknięciu tytułu uzyskasz szczegółowe informacje o wybranym filmie.

Jeśli buforujesz stronę szczegółów, szczegóły tego samego filmu będą wyświetlane bez względu na to, który film klikniesz. Pierwszy film wybrany przez pierwszego użytkownika będzie wyświetlany dla wszystkich przyszłych użytkowników.

Ten problem można rozwiązać, korzystając z właściwości VaryByParam atrybutu <OutputCache> . Ta właściwość umożliwia tworzenie różnych buforowanych wersji tej samej zawartości, gdy parametr formularza lub parametr ciągu zapytania różni się.

Na przykład kontroler w liście 5 uwidacznia dwie akcje o nazwie Master() i Details(). Akcja Master() zwraca listę tytułów filmu, a akcja Details() zwraca szczegóły wybranego filmu.

Lista 5 — Controllers\MoviesController.vb

Public Class MoviesController
    Inherits System.Web.Mvc.Controller

    Private _dataContext As MovieDataContext

    Public Sub New()
        _dataContext = New MovieDataContext()
    End Sub

    <OutputCache(Duration:=Integer.MaxValue, VaryByParam:="none")> _
    Public Function Master()
        ViewData.Model = (From m In _dataContext.Movies _
                          Select m).ToList()
        Return View()
    End Function

    <OutputCache(Duration:=Integer.MaxValue, VaryByParam:="id")> _
    Public Function Details(ByVal id As Integer)
        ViewData.Model = _dataContext.Movies.SingleOrDefault(Function(m) m.Id = id)
        Return View()
    End Function

End Class

Akcja Master() zawiera właściwość VaryByParam z wartością "none". Po wywołaniu akcji Master() zwracana jest ta sama buforowana wersja widoku głównego. Wszystkie parametry formularza lub parametry ciągu zapytania są ignorowane (zobacz Rysunek 2).

Rysunek 2 . Widok /Movies/Master

clip_image004

Rysunek 3 . Widok /Movies/Details

clip_image006

Akcja Details() zawiera właściwość VaryByParam o wartości "Id". Gdy do akcji kontrolera są przekazywane różne wartości parametru Identyfikator, generowane są różne buforowane wersje widoku Szczegóły.

Ważne jest, aby zrozumieć, że użycie właściwości VaryByParam powoduje więcej buforowania i nie mniej. Dla każdej innej wersji parametru Id jest tworzona inna buforowana wersja widoku Szczegóły.

Właściwość VaryByParam można ustawić na następujące wartości:

* = Utwórz inną wersję pamięci podręcznej za każdym razem, gdy parametr formularza lub ciągu zapytania różni się.

none = Nigdy nie twórz różnych wersji buforowanych

Lista średników parametrów = Tworzenie różnych buforowanych wersji za każdym razem, gdy dowolny z parametrów formularza lub ciągu zapytania na liście różni się

Tworzenie profilu pamięci podręcznej

Alternatywą dla konfigurowania właściwości wyjściowej pamięci podręcznej przez zmodyfikowanie właściwości atrybutu <OutputCache> można utworzyć profil pamięci podręcznej w pliku konfiguracji internetowej (web.config). Utworzenie profilu pamięci podręcznej w pliku konfiguracji sieci Web zapewnia kilka ważnych zalet.

Po pierwsze, konfigurując buforowanie danych wyjściowych w pliku konfiguracji internetowej, można kontrolować sposób buforowania zawartości w jednej centralnej lokalizacji przez akcje kontrolera. Można utworzyć jeden profil pamięci podręcznej i zastosować profil do kilku kontrolerów lub akcji kontrolera.

Po drugie możesz zmodyfikować plik konfiguracji sieci Web bez ponownego komplikowania aplikacji. Jeśli musisz wyłączyć buforowanie dla aplikacji, która została już wdrożona w środowisku produkcyjnym, możesz po prostu zmodyfikować profile pamięci podręcznej zdefiniowane w pliku konfiguracji sieci Web. Wszelkie zmiany w pliku konfiguracji sieci Web zostaną automatycznie wykryte i zastosowane.

Na przykład <sekcja konfiguracji sieci Web buforowania> w pozycji Lista 6 definiuje profil pamięci podręcznej o nazwie Cache1Hour. Sekcja <buforowania> musi być wyświetlana w <sekcji system.web> pliku konfiguracji sieci Web.

Lista 6 — sekcja buforowania dla web.config

<caching>
<outputCacheSettings>
    <outputCacheProfiles>
        <add name="Cache1Hour" duration="3600" varyByParam="none"/>
    </outputCacheProfiles>
</outputCacheSettings>
</caching>

Kontroler w liście 7 ilustruje, jak można zastosować profil Cache1Hour do akcji kontrolera z atrybutem <OutputCache> .

Lista 7 — Controllers\ProfileController.vb

Public Class ProfileController
    Inherits System.Web.Mvc.Controller

    <OutputCache(CacheProfile:="Cache1Hour")> _
    Function Index()
        Return DateTime.Now.ToString("T")
    End Function

End Class

Jeśli wywołasz akcję Index() uwidoczniona przez kontroler w liście 7, ten sam czas zostanie zwrócony przez 1 godzinę.

Podsumowanie

Buforowanie danych wyjściowych zapewnia bardzo łatwą metodę znacznie poprawy wydajności aplikacji ASP.NET MVC. W tym samouczku przedstawiono sposób użycia atrybutu <OutputCache> do buforowania danych wyjściowych akcji kontrolera. Przedstawiono również sposób modyfikowania właściwości atrybutu <OutputCache> , takiego jak właściwości Duration i VaryByParam w celu zmodyfikowania sposobu buforowania zawartości. Na koniec przedstawiono sposób definiowania profilów pamięci podręcznej w pliku konfiguracji sieci Web.