Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Autor : Scott Mitchell
Domyślny dostawca mapy witryny w ASP.NET 2.0 pobiera dane ze statycznego pliku XML. Chociaż dostawca oparty na formacie XML jest odpowiedni dla wielu małych i średnich witryn sieci Web, większe aplikacje internetowe wymagają bardziej dynamicznej mapy witryny. W tym samouczku utworzymy niestandardowego dostawcę mapy witryny, który pobiera dane z warstwy logiki biznesowej, a ta z kolei pobiera dane z bazy danych.
Wprowadzenie
funkcja mapy witryny ASP.NET 2.0 umożliwia deweloperowi strony zdefiniowanie mapy witryny aplikacji internetowej na nośniku trwałym, na przykład w pliku XML. Po zdefiniowaniu danych mapy witryny można uzyskać do nich programowy dostęp za pośrednictwem klasy w SiteMap przestrzeni nazw lub za pomocą różnych kontrolek nawigacji sieci Web, takich jak SiteMapPath, Menu i TreeView. System mapy lokacji używa modelu dostawcy, aby można było utworzyć i podłączyć do aplikacji internetowej różne implementacje serializacji mapy witryny. Domyślny dostawca mapy witryny dostarczany z ASP.NET 2.0 utrzymuje strukturę mapy witryny w pliku XML. W samouczku dotyczącym Stron Głównych i Nawigacji Witryny utworzyliśmy plik o nazwie Web.sitemap, który zawiera tę strukturę, a jego kod XML aktualizujemy przy każdej nowej sekcji samouczka.
Domyślny dostawca mapy witryny opartej na formacie XML sprawdza się, jeśli struktura mapy witryny jest dość statyczna, na przykład w przypadku tych samouczków. W wielu scenariuszach wymagana jest jednak bardziej dynamiczna mapa witryny. Rozważ mapę witryny pokazaną na rysunku 1, gdzie każda kategoria i produkt są wyświetlane jako sekcje w strukturze witryny internetowej. Korzystając z tej mapy witryny, przechodząc na stronę internetową odpowiadającą węzłowi głównemu, można zobaczyć listę wszystkich kategorii, podczas gdy przechodząc na stronę konkretnej kategorii, zostaną wyświetlone produkty tej kategorii, a przechodząc na stronę konkretnego produktu, zostaną pokazane szczegóły tego produktu.
Rysunek 1: Kategorie i produkty tworzą strukturę mapy witryny (kliknij, aby wyświetlić obraz pełnowymiarowy)
Chociaż ta struktura oparta na kategorii i produktach może być zakodowana w Web.sitemap pliku, plik musi zostać zaktualizowany za każdym razem, gdy kategoria lub produkt został dodany, usunięty lub zmieniony. W związku z tym konserwacja mapy lokacji byłaby znacznie uproszczona, jeśli jej struktura została pobrana z bazy danych lub, najlepiej, z warstwy logiki biznesowej architektury aplikacji. Dzięki temu, w miarę dodawania produktów i kategorii, zmiany nazwy lub usunięcia mapa witryny zostanie automatycznie zaktualizowana w celu odzwierciedlenia tych zmian.
Ponieważ serializacja mapy witryny w ASP.NET 2.0 oparta jest na modelu dostawcy, możemy utworzyć własnego, niestandardowego dostawcę mapy witryny, który pobiera dane z alternatywnego magazynu danych, takiego jak baza danych lub inna architektura. W tym samouczku utworzymy dostawcę niestandardowego, który pobiera dane z usługi BLL. Zacznijmy!
Uwaga
Niestandardowy dostawca mapy strony opisany w tym samouczku jest ściśle powiązany z architekturą i modelem danych aplikacji. Jeff Prosise omawia artykuły Przechowywanie map witryn w SQL Server i Dostawca map witryn SQL, na którego czekaliście, które badają uogólnione podejście do przechowywania danych map witryn w SQL Server.
Krok 1. Tworzenie dostosowanych stron internetowych dostawcy map witryn
Zanim zaczniemy tworzyć dostawcę niestandardowej mapy witryny, najpierw dodajmy strony ASP.NET, które będą potrzebne w tym samouczku. Zacznij od dodania nowego folderu o nazwie SiteMapProvider. Następnie dodaj następujące strony ASP.NET do tego folderu, aby skojarzyć każdą stronę ze stroną wzorcową Site.master :
Default.aspxProductsByCategory.aspxProductDetails.aspx
CustomProviders Dodaj również podfolder do App_Code folderu .
Rysunek 2. Dodaj strony ASP.NET do mapy witryny w samouczkach Provider-Related
Ponieważ w tej sekcji znajduje się tylko jeden samouczek, nie musimy Default.aspx wyświetlać listy samouczków sekcji.
Default.aspx Zamiast tego zostaną wyświetlone kategorie w kontrolce GridView. Zajmiemy się tym w kroku 2.
Następnie zaktualizuj element Web.sitemap , aby dołączyć odwołanie do Default.aspx strony. W szczególności dodaj następujący znacznik po cache'owaniu <siteMapNode>:
<siteMapNode
title="Customizing the Site Map" url="~/SiteMapProvider/Default.aspx"
description="Learn how to create a custom provider that retrieves the site map
from the Northwind database." />
Po zaktualizowaniu Web.sitemap, poświęć chwilę, aby wyświetlić witrynę samouczków w przeglądarce. Menu po lewej stronie zawiera teraz opcję dla samouczka dotyczącego dostawcy mapy witryny.
Mapa witryny teraz zawiera wpis dotyczący samouczka dla dostawcy mapy witryny.
Rysunek 3: Mapa witryny teraz zawiera wpis dotyczący samouczka dostawcy mapy witryny
Głównym celem tego samouczka jest zilustrowanie tworzenia niestandardowego dostawcy mapy witryny i konfigurowania aplikacji internetowej do korzystania z tego dostawcy. W szczególności utworzymy usługodawcę, który zwraca mapę witryny zawierającą węzeł główny wraz z węzłem dla każdej kategorii i produktu, jak przedstawiono na rysunku 1. Ogólnie rzecz biorąc, każdy węzeł na mapie witryny może określać adres URL. Dla naszej mapy witryny, adres URL węzła głównego to będzie ~/SiteMapProvider/Default.aspx, który będzie zawierać listę wszystkich kategorii w bazie danych. Każdy węzeł kategorii na mapie witryny będzie miał adres URL wskazujący na ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID, który będzie zawierał listę wszystkich produktów w określonej kategorii o identyfikatorze categoryID. Na koniec każdy węzeł mapy witryny produktu wskaże na element ~/SiteMapProvider/ProductDetails.aspx?ProductID=productID, który wyświetli szczegóły określonego produktu.
Aby rozpocząć, musimy utworzyć strony Default.aspx, ProductsByCategory.aspx i ProductDetails.aspx. Te strony są wypełniane kolejno w krokach 2, 3 i 4. Ponieważ główne założenie tego samouczka dotyczy dostawców map witryn, a ponieważ w poprzednich samouczkach omówiliśmy tworzenie tego typu wielostronicowych raportów głównych/szczegółowych, przejdziemy szybko przez kroki od 2 do 4. Jeśli potrzebujesz przypomnienia, jak tworzyć raporty typu główny/szczegółowy obejmujące wiele stron, odwołaj się do samouczka Filtrowanie główny/szczegółowy na dwóch stronach.
Krok 2. Wyświetlanie listy kategorii
Default.aspx Otwórz stronę w folderze SiteMapProvider i przeciągnij kontrolkę GridView z Narzędzi do projektanta, ustawiając jego właściwość ID na Categories. Z tagu inteligentnego GridView powiąż go z nowym obiektem ObjectDataSource o nazwie CategoriesDataSource i skonfiguruj go tak, aby pobierał swoje dane przy użyciu CategoriesBLL metody klasy s GetCategories . Ponieważ ten element GridView wyświetla tylko kategorie i nie udostępnia możliwości modyfikacji danych, ustaw listy rozwijane na kartach UPDATE, INSERT i DELETE na wartość (Brak).
Rysunek 4. Konfigurowanie obiektu ObjectDataSource do zwracania kategorii przy użyciu GetCategories metody (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Rysunek 5. Ustawianie list Drop-Down na kartach UPDATE, INSERT i DELETE na wartość (Brak) (Kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Po ukończeniu kreatora Konfigurowanie źródła danych program Visual Studio doda pole BoundField dla CategoryID, CategoryName, Description, NumberOfProducts i BrochurePath. Edytuj kontrolkę GridView, aby zawierała tylko pola CategoryName i Description, i zaktualizuj właściwość CategoryName BoundField do HeaderText Category.
Następnie dodaj pole HyperLinkField i umieść je tak, aby było to pole z lewej strony. Ustaw parametr DataNavigateUrlFields na CategoryID i DataNavigateUrlFormatString na ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}.
Text Ustaw właściwość na Wyświetl produkty .
Rysunek 6. Dodawanie pola HyperLinkField do kontrolki Categories GridView
Po utworzeniu kontrolki ObjectDataSource i dostosowaniu pól kontrolki GridView, znaczniki deklaratywne będą wyglądać następująco:
<asp:GridView ID="Categories" runat="server" AutoGenerateColumns="False"
DataKeyNames="CategoryID" DataSourceID="CategoriesDataSource"
EnableViewState="False">
<Columns>
<asp:HyperLinkField DataNavigateUrlFields="CategoryID"
DataNavigateUrlFormatString=
"~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}"
Text="View Products" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
SortExpression="CategoryName" />
<asp:BoundField DataField="Description" HeaderText="Description"
SortExpression="Description" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}" SelectMethod="GetCategories"
TypeName="CategoriesBLL"></asp:ObjectDataSource>
Rysunek 7 pokazuje Default.aspx wyświetlany w przeglądarce. Kliknięcie linku Wyświetl produkty kategorii spowoduje przejście do ProductsByCategory.aspx?CategoryID=categoryID, który utworzymy w kroku 3.
Rysunek 7. Każda kategoria jest wyświetlana wraz z linkiem Wyświetl produkty (kliknij, aby wyświetlić obraz pełnowymiarowy)
Krok 3. Wyświetlanie listy wybranych produktów kategorii
ProductsByCategory.aspx Otwórz stronę i dodaj kontrolkę GridView, nazewając ją ProductsByCategory. Z inteligentnego tagu powiąż element GridView z nowym obiektem ObjectDataSource o nazwie ProductsByCategoryDataSource. Skonfiguruj ObjectDataSource do używania metody GetProductsByCategoryID(categoryID) klasy ProductsBLL i ustaw listy rozwijane na (Brak) w kartach UPDATE, INSERT i DELETE.
Rysunek 8. Użycie ProductsBLL metody klasy GetProductsByCategoryID(categoryID) (kliknij, aby wyświetlić obraz pełnowymiarowy)
Ostatni krok w kreatorze Konfigurowania źródła danych prosi o podanie źródła parametrów dla categoryID. Ponieważ te informacje są przekazywane przez pole CategoryIDQueryString, wybierz pozycję QueryString z listy rozwijanej i wprowadź CategoryID w polu tekstowym QueryStringField, jak pokazano na rysunku 9. Kliknij Zakończ, aby zakończyć kreatora.
Rysunek 9. Użyj pola querystring dla parametru CategoryIDcategoryID (kliknij, aby wyświetlić obraz pełnowymiarowy)
Po ukończeniu pracy kreatora program Visual Studio doda odpowiednie pola BoundFields i CheckBoxField do kontrolki GridView dla pól danych produktu. Usuń wszystkie elementy, oprócz ProductName, UnitPrice i SupplierName BoundFields. Dostosuj te trzy właściwości BoundFields HeaderText , aby odpowiednio odczytywać pozycje Produkt, Cena i Dostawca. Formatuj pole UnitPrice BoundField jako walutę.
Następnie dodaj pole HyperLinkField i przenieś je do lewej pozycji. Ustaw jej Text właściwość na Wyświetl szczegóły, jej DataNavigateUrlFields właściwość na ProductID, a jej DataNavigateUrlFormatString właściwość na ~/SiteMapProvider/ProductDetails.aspx?ProductID={0}.
Rysunek 10. Dodaj pole HyperLinkField 'View Details' skierowane na ProductDetails.aspx
Po wprowadzeniu tych dostosowań, znaczniki deklaratywne GridView i ObjectDataSource powinny wyglądać podobnie do następujących:
<asp:GridView ID="ProductsByCategory" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsByCategoryDataSource"
EnableViewState="False">
<Columns>
<asp:HyperLinkField DataNavigateUrlFields="ProductID"
DataNavigateUrlFormatString=
"~/SiteMapProvider/ProductDetails.aspx?ProductID={0}"
Text="View Details" />
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False"
SortExpression="UnitPrice" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True" SortExpression="SupplierName" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsByCategoryDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
<SelectParameters>
<asp:QueryStringParameter Name="categoryID"
QueryStringField="CategoryID" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
Wróć do przeglądania Default.aspx za pośrednictwem przeglądarki i kliknij link „Wyświetl produkty” dla kategorii napojów. To przeniesie cię do ProductsByCategory.aspx?CategoryID=1, gdzie zostaną wyświetlone nazwy, ceny i dostawcy produktów w bazie danych Northwind należących do kategorii Napoje (patrz Rysunek 11). Możesz dodatkowo ulepszyć tę stronę, aby dołączyć link umożliwiający zwrócenie użytkowników do strony listy kategorii (Default.aspx) oraz kontrolki DetailsView lub FormView, która wyświetla nazwę i opis wybranej kategorii.
Rysunek 11. Wyświetlane są nazwy napojów, ceny i dostawcy (kliknij, aby wyświetlić obraz pełnowymiarowy)
Krok 4. Wyświetlanie szczegółów produktu
Ostatnia strona , ProductDetails.aspxwyświetla szczegóły wybranych produktów. Otwórz ProductDetails.aspx element DetailsView z przybornika i przeciągnij go do projektanta. Ustaw właściwość ID kontrolki DetailsView na ProductInfo i wyczyść wartości właściwości Height oraz Width. Na podstawie tagu inteligentnego powiąż element DetailsView z nowym obiektem ObjectDataSource o nazwie ProductDataSource, konfigurując obiekt ObjectDataSource w celu ściągnięcia danych z ProductsBLL metody klasy s GetProductByProductID(productID) . Podobnie jak w przypadku poprzednich stron internetowych utworzonych w krokach 2 i 3, ustaw listy rozwijane na kartach UPDATE, INSERT i DELETE na wartość (Brak).
Rysunek 12. Konfigurowanie obiektu ObjectDataSource do użycia GetProductByProductID(productID) metody (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
W ostatnim kroku kreatora Konfigurowania źródła danych zostanie wyświetlony monit o podanie źródła parametru productID . Ponieważ te dane przechodzą przez pole ProductID QueryString, ustaw listę rozwijaną na QueryString i pole tekstowe QueryStringField na ProductID. Na koniec kliknij przycisk Zakończ, aby ukończyć pracę kreatora.
Rysunek 13. Konfigurowanie parametru productID w celu ściągnięcia jego wartości z ProductID pola Ciąg zapytania (kliknij, aby wyświetlić obraz pełnowymiarowy)
Po zakończeniu pracy kreatora "Konfigurowanie źródła danych" program Visual Studio utworzy odpowiednie pola powiązane i pole wyboru w widoku szczegółów dla pól danych produktu. Usuń ProductID, SupplierID i CategoryID BoundFields i skonfiguruj pozostałe pola według własnego uznania. Po kilku konfiguracjach estetycznych moje znaczniki deklaratywne DetailsView i ObjectDataSource wyglądały następująco:
<asp:DetailsView ID="ProductInfo" runat="server" AutoGenerateRows="False"
DataKeyNames="ProductID" DataSourceID="ProductDataSource"
EnableViewState="False">
<Fields>
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category"
ReadOnly="True" SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier"
ReadOnly="True" SortExpression="SupplierName" />
<asp:BoundField DataField="QuantityPerUnit" HeaderText="Qty/Unit"
SortExpression="QuantityPerUnit" />
<asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
HeaderText="Price" HtmlEncode="False"
SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock" HeaderText="Units In Stock"
SortExpression="UnitsInStock" />
<asp:BoundField DataField="UnitsOnOrder" HeaderText="Units On Order"
SortExpression="UnitsOnOrder" />
<asp:BoundField DataField="ReorderLevel" HeaderText="Reorder Level"
SortExpression="ReorderLevel" />
<asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued"
SortExpression="Discontinued" />
</Fields>
</asp:DetailsView>
<asp:ObjectDataSource ID="ProductDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProductByProductID" TypeName="ProductsBLL">
<SelectParameters>
<asp:QueryStringParameter Name="productID"
QueryStringField="ProductID" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
Aby przetestować tę stronę, wróć do Default.aspx i kliknij pozycję Wyświetl produkty dla kategorii Napoje. Na liście produktów napojów kliknij link Wyświetl szczegóły dla Chai Tea. Spowoduje to przejście do ProductDetails.aspx?ProductID=1, w którym zostaną wyświetlone szczegóły herbaty Chai (patrz Rysunek 14).
Rysunek 14: Wyświetlane są informacje o dostawcy, kategorii, cenie i innych danych dotyczących Chai Tea (Kliknij, aby wyświetlić obraz pełnowymiarowy)
Krok 5. Zrozumienie wewnętrznego działania dostawcy mapy lokacji
Mapa witryny jest reprezentowana w pamięci serwera internetowego jako zbiór SiteMapNode wystąpień, które tworzą hierarchię. Musi istnieć dokładnie jeden węzeł główny, wszystkie węzły inne niż węzeł główny muszą mieć dokładnie jeden węzeł nadrzędny, a wszystkie węzły mogą mieć dowolną liczbę węzłów podrzędnych. Każdy SiteMapNode obiekt reprezentuje sekcję w strukturze witryny internetowej. Te sekcje często mają odpowiednią stronę internetową.
SiteMapNode
W związku z tym klasa ma właściwości takie jak Title, Urli Description, które zawierają informacje dotyczące sekcji reprezentowanej przez klasę SiteMapNode . Istnieje również Key właściwość, która jednoznacznie identyfikuje każdy SiteMapNode w hierarchii, a także właściwości używane do ustanowienia tej hierarchii ChildNodes, ParentNode, NextSibling, PreviousSibling i tak dalej.
Rysunek 15 przedstawia ogólną strukturę mapy witryny z rysunku 1, ale szczegóły implementacji zostały przedstawione bardziej szczegółowo.
Rysunek 15. Każda z nich SiteMapNode ma właściwości takie jak Title, Url, Keyi tak dalej (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Mapa witryny jest dostępna za pośrednictwem SiteMap klasy w System.Web przestrzeni nazw. Ta właściwość tej klasy RootNode zwraca główne wystąpienie SiteMapNode mapy witryny. CurrentNode Zwraca wystąpienie SiteMapNode, którego Url właściwość odpowiada URL aktualnie żądanej strony. Ta klasa jest używana wewnętrznie przez kontrolki nawigacji sieci Web ASP.NET 2.0.
SiteMap Gdy uzyskuje się dostęp do właściwości klasy, należy serializować strukturę mapy witryny z określonego nośnika trwałego do pamięci. Jednak logika serializacji mapy witryny nie jest zakodowana w SiteMap klasie. Zamiast tego, w czasie wykonywania klasa SiteMap określa, który dostawca mapy witryny ma być używany do serializacji. Domyślnie XmlSiteMapProvider jest używana klasa, która odczytuje strukturę mapy witryny z poprawnie sformatowanego pliku XML. Jednak przy odrobinie pracy możemy utworzyć własnego niestandardowego dostawcę map witryn.
Wszyscy dostawcy map witryn muszą pochodzić z SiteMapProvider klasy, która zawiera podstawowe metody i właściwości wymagane dla dostawców mapy lokacji, ale pomija wiele szczegółów implementacji. Druga klasa, StaticSiteMapProvider, rozszerza klasę SiteMapProvider i zawiera bardziej niezawodną implementację wymaganych funkcji. Wewnętrznie program StaticSiteMapProvider przechowuje SiteMapNode wystąpienia mapy witryny w obiekcie Hashtable i udostępnia metody, takie jak AddNode(child, parent), RemoveNode(siteMapNode), oraz Clear(), które dodają i usuwają SiteMapNode do wewnętrznego elementu Hashtable.
XmlSiteMapProvider pochodzi z StaticSiteMapProvider.
Podczas tworzenia niestandardowego dostawcy mapy witryny rozszerzającego StaticSiteMapProvider, istnieją dwie abstrakcyjne metody, które muszą zostać nadpisane: BuildSiteMap i GetRootNodeCore.
BuildSiteMap, jak wskazuje jego nazwa, jest odpowiedzialny za ładowanie struktury mapy strony z pamięci trwałej i konstruowanie jej w pamięci.
GetRootNodeCore Zwraca węzeł główny na mapie witryny.
Aby aplikacja internetowa mogła korzystać z dostawcy mapy witryny, musi zostać zarejestrowana w konfiguracji aplikacji. Domyślnie klasa XmlSiteMapProvider jest rejestrowana przy użyciu nazwy AspNetXmlSiteMapProvider. Aby zarejestrować dodatkowych dostawców map witryn, dodaj następujący znacznik do :Web.config
<configuration>
<system.web>
...
<siteMap defaultProvider="defaultProviderName">
<providers>
<add name="name" type="type" />
</providers>
</siteMap>
</system.web>
</configuration>
Wartość nazwy przypisuje do dostawcy nazwę czytelną dla człowieka, podczas gdy typ określa w pełni kwalifikowaną nazwę typu dostawcy mapy lokacji. Poznamy konkretne wartość 'nazwa' i 'typ' w kroku 7, gdy już stworzymy własnego dostawcę mapy witryny.
Klasa dostawcy mapy witryny jest tworzona po raz pierwszy z klasy SiteMap i pozostaje w pamięci na czas działania aplikacji internetowej. Ponieważ istnieje tylko jedno wystąpienie dostawcy mapy witryny, które może być wywoływane z wielu, współbieżnych odwiedzających witrynę internetową, konieczne jest, aby metody dostawcy były bezpieczne wątkowo.
Ze względu na wydajność i skalowalność ważne jest, aby buforować strukturę mapy lokacji w pamięci i zwracać tę buforowana strukturę, a nie odtwarzać ją za każdym razem, gdy BuildSiteMap metoda jest wywoływana.
BuildSiteMap Może być wywoływany kilka razy na żądanie strony dla użytkownika, w zależności od kontrolek nawigacji używanych na stronie i głębokości struktury mapy witryny. W każdym przypadku, jeśli nie buforujemy struktury mapy witryny w BuildSiteMap, to za każdym razem, gdy jest wywoływana, musielibyśmy ponownie pobrać informacje o produkcie i kategorii z systemu (co spowodowałoby wysłanie zapytania do bazy danych). Jak omówiono w poprzednich samouczkach buforowania, buforowane dane mogą stać się nieaktualne. Aby temu przeciwdziałać, możemy użyć wygaśnięcia opartego na czasie lub zależności od pamięci podręcznej SQL.
Uwaga
Dostawca mapy witryny może opcjonalnie zastąpić metodęInitialize .
Initialize jest wywoływany, gdy dostawca mapy lokacji jest po raz pierwszy zainicjowany i przekazywane są wszelkie atrybuty niestandardowe przypisane do dostawcy w elemencie Web.config takie jak: <add name="name" type="type" customAttribute="value" />. Jest to przydatne, jeśli chcesz zezwolić deweloperowi strony na określanie różnych ustawień związanych z dostawcą mapy witryny bez konieczności modyfikowania kodu dostawcy. Jeśli na przykład odczytywalibyśmy dane kategorii i produktów bezpośrednio z bazy danych zamiast poprzez architekturę, prawdopodobnie chcielibyśmy umożliwić deweloperowi strony określenie parametrów połączenia z bazą danych za pomocą Web.config zamiast użycia twardo zakodowanej wartości w kodzie dostawcy. Niestandardowy dostawca mapy witryny, który utworzymy w kroku 6, nie zastępuje tej Initialize metody. Aby zapoznać się z przykładem użycia metody Initialize, zapoznaj się z artykułem Storing Site Maps in SQL Server autorstwa Jeffa Prosise'a.
Krok 6: Tworzenie niestandardowego dostawcy mapy witryny
Aby utworzyć niestandardowego dostawcę mapy witryny, który kompiluje mapę witryny z kategorii i produktów w bazie danych Northwind, musimy utworzyć klasę rozszerzającą StaticSiteMapProvider. W kroku 1 poprosiłem Cię o dodanie folderu CustomProviders wewnątrz folderu App_Code — dodaj do tego folderu nową klasę o nazwie NorthwindSiteMapProvider. Dodaj następujący kod do NorthwindSiteMapProvider klasy:
Imports System.Web
Imports System.Web.Caching
Public Class NorthwindSiteMapProvider
Inherits StaticSiteMapProvider
Private ReadOnly siteMapLock As New Object()
Private root As SiteMapNode = Nothing
Public Const CacheDependencyKey As String = "NorthwindSiteMapProviderCacheDependency"
Public Overrides Function BuildSiteMap() As System.Web.SiteMapNode
' Use a lock to make this method thread-safe
SyncLock siteMapLock
' First, see if we already have constructed the
' rootNode. If so, return it...
If root IsNot Nothing Then
Return root
End If
' We need to build the site map!
' Clear out the current site map structure
MyBase.Clear()
' Get the categories and products information from the database
Dim productsAPI As New ProductsBLL()
Dim products As Northwind.ProductsDataTable = productsAPI.GetProducts()
' Create the root SiteMapNode
root = New SiteMapNode( _
Me, "root", "~/SiteMapProvider/Default.aspx", "All Categories")
AddNode(root)
' Create SiteMapNodes for the categories and products
For Each product As Northwind.ProductsRow In products
' Add a new category SiteMapNode, if needed
Dim categoryKey, categoryName As String
Dim createUrlForCategoryNode As Boolean = True
If product.IsCategoryIDNull() Then
categoryKey = "Category:None"
categoryName = "None"
createUrlForCategoryNode = False
Else
categoryKey = String.Concat("Category:", product.CategoryID)
categoryName = product.CategoryName
End If
Dim categoryNode As SiteMapNode = FindSiteMapNodeFromKey(categoryKey)
' Add the category SiteMapNode if it does not exist
If categoryNode Is Nothing Then
Dim productsByCategoryUrl As String = String.Empty
If createUrlForCategoryNode Then
productsByCategoryUrl = _
"~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=" & _
product.CategoryID
End If
categoryNode = New SiteMapNode _
(Me, categoryKey, productsByCategoryUrl, categoryName)
AddNode(categoryNode, root)
End If
' Add the product SiteMapNode
Dim productUrl As String = _
"~/SiteMapProvider/ProductDetails.aspx?ProductID=" & _
product.ProductID
Dim productNode As New SiteMapNode _
(Me, String.Concat("Product:", product.ProductID), _
productUrl, product.ProductName)
AddNode(productNode, categoryNode)
Next
' Add a "dummy" item to the cache using a SqlCacheDependency
' on the Products and Categories tables
Dim productsTableDependency As New _
System.Web.Caching.SqlCacheDependency("NorthwindDB", "Products")
Dim categoriesTableDependency As New _
System.Web.Caching.SqlCacheDependency("NorthwindDB", "Categories")
' Create an AggregateCacheDependency
Dim aggregateDependencies As New System.Web.Caching.AggregateCacheDependency()
aggregateDependencies.Add(productsTableDependency, categoriesTableDependency)
' Add the item to the cache specifying a callback function
HttpRuntime.Cache.Insert( _
CacheDependencyKey, DateTime.Now, aggregateDependencies, _
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, _
CacheItemPriority.Normal, AddressOf OnSiteMapChanged)
' Finally, return the root node
Return root
End SyncLock
End Function
Protected Overrides Function GetRootNodeCore() As System.Web.SiteMapNode
Return BuildSiteMap()
End Function
Protected Sub OnSiteMapChanged _
(key As String, value As Object, reason As CacheItemRemovedReason)
SyncLock siteMapLock
If String.Compare(key, CacheDependencyKey) = 0 Then
' Refresh the site map
root = Nothing
End If
End SyncLock
End Sub
Public ReadOnly Property CachedDate() As Nullable(Of DateTime)
Get
Dim value As Object = HttpRuntime.Cache(CacheDependencyKey)
If value Is Nothing OrElse Not TypeOf value Is Nullable(Of DateTime) Then
Return Nothing
Else
Return CType(value, Nullable(Of DateTime))
End If
End Get
End Property
End Class
Rozpocznijmy od badania tej metody klasylock umożliwia wejście tylko jednego wątku naraz, co serializuje dostęp do kodu i zapobiega wzajemnemu przeszkadzaniu się dwóch współbieżnych wątków.
Zmienna SiteMapNode na poziomie root klasy służy do buforowania struktury mapy witryny. Po utworzeniu mapy lokacji po raz pierwszy lub po raz pierwszy po zmodyfikowaniu root danych bazowych zostanie Nothing utworzona struktura mapy lokacji. Główny węzeł mapy lokacji jest przypisywany do root podczas procesu budowy, tak aby przy następnym wywołaniu tej metody root nie był Nothing. W związku z tym, tak długo, jak root nie jest Nothing, struktura mapy witryny zostanie zwrócona do obiektu wywołującego bez konieczności jej ponownego tworzenia.
Jeśli katalog główny to Nothing, struktura mapy witryny jest tworzona na podstawie informacji o produkcie i kategorii. Mapa witryny jest budowana przez stworzenie instancji SiteMapNode, a następnie tworzenie hierarchii poprzez wywołania metody AddNode klasy StaticSiteMapProvider.
AddNode wykonuje wewnętrzne księgowanie, przechowując wystąpienia assortowane SiteMapNode w obiekcie Hashtable. Zanim rozpoczniemy konstruowanie hierarchii, najpierw wywołujemy metodę Clear, która usuwa elementy z wewnętrznego Hashtable. Metoda s GetProducts klasy ProductsBLL oraz wynikowe ProductsDataTable są następnie przechowywane w zmiennych lokalnych.
Budowa mapy lokacji rozpoczyna się od utworzenia węzła głównego oraz jego przypisania do elementu root. Przeciążenie konstruktora SiteMapNode s używanego tutaj i w całym BuildSiteMap miejscu przekazuje następujące informacje:
- Odwołanie do dostawcy mapy witryny (
Me). -
SiteMapNodesKey. Ta wymagana wartość musi być unikatowa dla każdegoSiteMapNodeelementu . -
SiteMapNodesUrl.Urlwartość jest opcjonalna, ale jeśli jest podana, każdaSiteMapNodewartość sUrlmusi być unikatowa. - Parametr
SiteMapNodesTitle, który jest niezbędny.
Wywołanie metody AddNode(root) dodaje element SiteMapNoderoot do mapy witryny jako korzeń. Następnie każda ProductRow w ProductsDataTable jest wyliczana. Jeśli dla bieżącej kategorii produktu już istnieje SiteMapNode, jest on przywoływany. W przeciwnym razie zostanie utworzony nowy SiteMapNode dla kategorii i dodany jako element podrzędny do SiteMapNode``root przez wywołanie AddNode(categoryNode, root). Po znalezieniu lub utworzeniu odpowiedniego węzła kategorii SiteMapNode zostanie SiteMapNode utworzony dla bieżącego produktu i dodany jako element podrzędny kategorii SiteMapNode za pośrednictwem metody AddNode(productNode, categoryNode). Należy pamiętać, że wartość właściwości kategorii SiteMapNode to Url, podczas gdy właściwość produktu ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID jest przypisana SiteMapNode.
Uwaga
Te produkty, które mają wartość bazy danych NULL dla nich CategoryID , są grupowane w kategorii SiteMapNode , której Title właściwość jest ustawiona na None i której Url właściwość jest ustawiona na pusty ciąg. Postanowiłem ustawić Url na pusty ciąg, ponieważ metoda klasy s GetProductsByCategory(categoryID) obecnie nie ma możliwości zwrócenia tylko tych produktów z wartością NULLCategoryID. Chcę również zademonstrować, w jaki sposób sterowanie nawigacją renderuje element SiteMapNode, który nie ma wartości dla jego Url właściwości. Zachęcam do rozszerzenia tego samouczka tak, aby właściwość None SiteMapNodeUrl wskazywała na ProductsByCategory.aspx, lecz wyświetlała tylko te produkty, które mają wartości NULLCategoryID.
Po utworzeniu mapy witryny, dowolny obiekt jest dodawany do pamięci podręcznej danych z użyciem zależności pamięci podręcznej SQL dla tabel Categories i Products za pośrednictwem obiektu AggregateCacheDependency. W poprzednim samouczku zapoznaliśmy się z użyciem zależności pamięci podręcznej SQL, korzystając z zależności pamięci podręcznej SQL. Niestandardowy dostawca mapy witryny używa jednak przeciążonej wersji metody Insert pamięci podręcznej danych, której jeszcze nie zbadaliśmy. To przeciążenie przyjmuje jako końcowy parametr wejściowy delegata, który jest wywoływany po usunięciu obiektu z pamięci podręcznej. W szczególności przekazujemy nowego CacheItemRemovedCallback delegata , który wskazuje metodę zdefiniowaną OnSiteMapChanged dalej w dół w NorthwindSiteMapProvider klasie.
Uwaga
Reprezentacja mapy witryny w pamięci jest buforowana za pomocą zmiennej rootna poziomie klasy . Ponieważ istnieje tylko jedno wystąpienie niestandardowej klasy dostawcy mapy witryny i ponieważ to wystąpienie jest współużytkowane przez wszystkie wątki w aplikacji internetowej, ta zmienna klasy służy jako pamięć podręczna. Metoda BuildSiteMap używa również pamięci podręcznej danych, ale tylko jako środek do odbierania powiadomień, gdy bazowe dane bazy danych w Categories tabelach lub Products zmieniają się. Należy pamiętać, że wartość umieszczona w pamięci podręcznej danych to tylko bieżąca data i godzina. Rzeczywiste dane mapy witryny nie są umieszczane w pamięci podręcznej danych.
Metoda BuildSiteMap zostanie ukończona przez zwrócenie węzła głównego mapy witryny.
Pozostałe metody są dość proste.
GetRootNodeCore jest odpowiedzialny za zwracanie węzła głównego. Ponieważ BuildSiteMap zwraca element główny, GetRootNodeCore po prostu zwraca BuildSiteMap wartość zwracaną przez element s. Metoda OnSiteMapChanged ustawia root z powrotem do Nothing, gdy element pamięci podręcznej zostanie usunięty. Po ponownym ustawieniu głównego na Nothing, przy następnym wywołaniu BuildSiteMap struktura mapy witryny zostanie ponownie skompilowana.
CachedDate Na koniec właściwość zwraca wartość daty i godziny przechowywaną w pamięci podręcznej danych, jeśli taka wartość istnieje. Ta właściwość może być używana przez dewelopera strony w celu określenia, kiedy dane mapy witryny były ostatnio buforowane.
Krok 7. RejestrowanieNorthwindSiteMapProvider
Aby nasza aplikacja internetowa korzystała z dostawcy mapy witryny utworzonego w kroku 6 przez NorthwindSiteMapProvider, musimy zarejestrować go w sekcji <siteMap>Web.config. W szczególności dodaj następujący znacznik w elemencie <system.web> w Web.config:
<siteMap defaultProvider="AspNetXmlSiteMapProvider">
<providers>
<add name="Northwind" type="NorthwindSiteMapProvider" />
</providers>
</siteMap>
Ten znacznik wykonuje dwie czynności: najpierw wskazuje, że wbudowany AspNetXmlSiteMapProvider jest domyślnym dostawcą mapy witryny; następnie rejestruje niestandardowego dostawcę mapy witryny utworzonego w kroku 6, za pomocą przyjaznej dla człowieka nazwy Northwind.
Uwaga
W przypadku dostawców map witryn znajdujących się w folderze aplikacji App_Code wartość atrybutu type jest po prostu nazwą klasy. Alternatywnie niestandardowy dostawca mapy witryny mógł zostać utworzony w osobnym projekcie biblioteki klas z skompilowanym zestawem umieszczonym w katalogu aplikacji /Bin internetowej. W takim przypadku wartością atrybutu type będzie przestrzeń nazw.ClassName, AssemblyName .
Po zaktualizowaniu Web.config, poświęć chwilę, żeby wyświetlić dowolną stronę z samouczków w przeglądarce. Pamiętaj, że interfejs nawigacyjny po lewej stronie nadal zawiera sekcje i samouczki zdefiniowane w pliku Web.sitemap. Jest to spowodowane tym, że pozostawiliśmy AspNetXmlSiteMapProvider go jako domyślnego dostawcę. Aby utworzyć element interfejsu użytkownika nawigacji wykorzystujący NorthwindSiteMapProvider, należy wyraźnie określić, że trzeba użyć dostawcy mapy witryny Northwind. Zobaczymy, jak to zrobić w kroku 8.
Krok 8. Wyświetlanie informacji o mapie witryny przy użyciu niestandardowego dostawcy mapy witryny
Za pomocą niestandardowego dostawcy mapy witryny utworzonego i zarejestrowanego w Web.config możemy dodać elementy nawigacyjne do Default.aspx, ProductsByCategory.aspx i ProductDetails.aspx w folderze SiteMapProvider. Zacznij od otwarcia Default.aspx strony i przeciągnięcia SiteMapPath elementu z przybornika do projektanta. Kontrolka SiteMapPath znajduje się w sekcji Nawigacja w przyborniku.
Rysunek 16. Dodawanie ścieżki SiteMapPath do Default.aspx (kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Kontrolka SiteMapPath wyświetla ślad nawigacyjny, wskazując bieżącą lokalizację strony w strukturze mapy witryny. Dodaliśmy SiteMapPath na górze strony wzorcowej w samouczku Strony wzorcowe i Nawigacja witryny.
Poświęć chwilę, aby wyświetlić tę stronę w przeglądarce. Ścieżka SiteMapPath dodana na rysunku 16 używa domyślnego dostawcy map witryn, pobierając dane z Web.sitemap. W związku z tym ścieżka nawigacyjna pokazuje Home > Customizing the Site Map, podobnie jak ścieżka nawigacyjna w prawym górnym rogu.
Rysunek 17: Nawigacja okruszkowa używa domyślnego dostawcy mapy witryny (Kliknij, aby zobaczyć obraz w pełnym rozmiarze)
Aby obiekt SiteMapPath został dodany na Rysunku 16, użyj niestandardowego dostawcy mapy witryny utworzonego w Kroku 6, ustaw jego SiteMapProvider właściwość na Northwind, nazwę przypisaną do NorthwindSiteMapProvider w Web.config. Niestety program nadal używa domyślnego dostawcy mapy witryny, ale jeśli odwiedzisz stronę za pośrednictwem przeglądarki po wprowadzeniu tej zmiany w ustawieniach, zobaczysz, że ścieżka nawigacji teraz używa niestandardowego dostawcy mapy witryny.
Rysunek 18: Okruszki nawigacyjne teraz używają niestandardowego dostawcy mapy witryny (NorthwindSiteMapProvider)
Kontrolka SiteMapPath wyświetla bardziej funkcjonalny interfejs użytkownika na stronach ProductsByCategory.aspx i ProductDetails.aspx. Dodaj SiteMapPath do tych stron, ustawiając właściwość SiteMapProvider w obu stronach na Northwind. Kliknij link Default.aspx "Wyświetl produkty" dla napojów, a następnie "Wyświetl szczegóły" dla herbaty Chai. Jak pokazano na rysunku 19, okruszki nawigacyjne obejmują bieżącą sekcję mapy witryny (Chai Tea) i poprzedzające sekcje: napoje i wszystkie kategorie.
Rysunek 19: Nawigacja okruszkowa teraz używa niestandardowego dostawcy mapy witryny NorthwindSiteMapProvider (Kliknij, aby wyświetlić pełnowymiarowy obraz)
Inne elementy interfejsu użytkownika nawigacji można używać oprócz kontrolki SiteMapPath, takich jak Menu i TreeView.
Default.aspx Strony ProductsByCategory.aspx, i ProductDetails.aspx w plikach pobranych dla tego samouczka, na przykład, zawierają wszystkie kontrolki Menu (zobacz Rysunek 20). Zobacz Zaawansowane funkcje nawigacji witryny w ASP.NET 2.0 oraz sekcję Używanie kontrolek nawigacyjnych w ASP.NET 2.0 QuickStarts, aby uzyskać bardziej szczegółowe informacje na temat kontrolek nawigacji i systemu mapy witryny w ASP.NET 2.0.
Rysunek 20. Kontrolka menu wyświetla listę poszczególnych kategorii i produktów (kliknij, aby wyświetlić obraz pełnowymiarowy)
Jak wspomniano wcześniej w tym samouczku, dostęp do struktury mapy witryny można uzyskać programowo za pośrednictwem SiteMap klasy . Poniższy kod zwraca rdzeń SiteMapNode domyślnego dostawcy:
Dim root As SiteMapNode = SiteMap.RootNode
AspNetXmlSiteMapProvider Ponieważ jest to domyślny dostawca naszej aplikacji, powyższy kod zwróci węzeł główny zdefiniowany w pliku Web.sitemap. Aby odwołać się do dostawcy mapy witryny innej niż domyślna, użyj SiteMap właściwości klasy s Providers w następujący sposób:
Dim root As SiteMapNode = SiteMap.Providers("name").RootNode
Gdzie nazwa jest nazwą własnego dostawcy mapy witryny (Northwind dla aplikacji internetowej).
Aby uzyskać dostęp do elementu członka specyficznego dla dostawcy mapy witryny, użyj SiteMap.Providers["name"] do pobrania instancji dostawcy, a następnie rzutuj ją do odpowiedniego typu. Aby na przykład wyświetlić właściwość NorthwindSiteMapProvider s CachedDate na stronie ASP.NET, użyj następującego kodu:
Dim customProvider As NorthwindSiteMapProvider = _
TryCast(SiteMap.Providers("Northwind"), NorthwindSiteMapProvider)
If customProvider IsNot Nothing Then
Dim lastCachedDate As Nullable(Of DateTime) = customProvider.CachedDate
If lastCachedDate.HasValue Then
SiteMapLastCachedDate.Text = _
"Site map cached on: " & lastCachedDate.Value.ToString()
Else
SiteMapLastCachedDate.Text = "The site map is being reconstructed!"
End If
End If
Uwaga
Pamiętaj, aby przetestować funkcję zależności pamięci podręcznej SQL. Po przejściu na strony Default.aspx, ProductsByCategory.aspx i ProductDetails.aspx, przejdź do jednego z samouczków w sekcji Edytowanie, Wstawianie i Usuwanie, a następnie edytuj nazwę kategorii lub produktu. Następnie wróć do jednej ze stron w folderze SiteMapProvider . Zakładając, że dla mechanizmu sondowania minęło wystarczająco dużo czasu, aby zanotować zmianę w bazowej bazie danych, mapa witryny powinna zostać zaktualizowana w celu wyświetlenia nowej nazwy produktu lub kategorii.
Podsumowanie
Funkcje mapy witryny ASP.NET 2.0 obejmują klasę SiteMap, szereg wbudowanych kontrolek nawigacyjnych sieci Web oraz domyślnego dostawcę mapy witryny, który oczekuje, że informacje o mapie witryny są utrwalone w pliku XML. Aby użyć informacji o mapie witryny z innego źródła, takiego jak z bazy danych, architektury aplikacji lub zdalnej usługi sieci Web, musimy utworzyć niestandardowego dostawcę mapy witryny. Obejmuje to utworzenie klasy, która pochodzi bezpośrednio lub pośrednio z SiteMapProvider klasy .
W tym samouczku omówiliśmy, jak utworzyć niestandardowego dostawcę mapy witryny opartego na informacji o produkcie i kategorii wydobytych z architektury aplikacji. Nasz dostawca rozszerzył klasę StaticSiteMapProvider i wymagało to utworzenia metody BuildSiteMap, która pobierała dane, konstruowała hierarchię mapy lokacji oraz buforowała wynikową strukturę w zmiennej na poziomie klasy. Użyliśmy zależności pamięci podręcznej SQL z funkcją wywołania zwrotnego, aby unieważnić buforowaną strukturę podczas modyfikowania bazowych Categories danych lub Products danych.
Szczęśliwe programowanie!
Dalsze informacje
Aby uzyskać więcej informacji na temat tematów omówionych w tym samouczku, zapoznaj się z następującymi zasobami:
- Przechowywanie map witryn w programie SQL Server i dostawca map witryn SQL, na którego czekałeś
- Zestaw narzędzi dostawcy
- zaawansowane funkcje nawigacji witryny w wersji ASP.NET 2.0
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 dla tego samouczka to Dave Gardner, Zack Jones, Teresa Murphy i Bernadette Leigh. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, napisz do mnie na adres mitchell@4GuysFromRolla.com.