Tworzenie niestandardowego dostawcy map witryn opartych na bazie danych (C#)
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, który 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 można uzyskać dostęp do danych mapy witryny programowo za pośrednictwem klasy w System.Web
przestrzeni nazw lub za pomocą SiteMap
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 wzorcowych i nawigacji witryny utworzyliśmy plik o nazwie Web.sitemap
zawierający tę strukturę i zaktualizowaliśmy kod XML przy użyciu 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. Na tej mapie witryny odwiedź stronę internetową odpowiadającą węzłowi głównemu może wyświetlić listę wszystkich kategorii, podczas gdy odwiedzanie określonej strony sieci Web kategorii spowoduje wyświetlenie tej kategorii produktów i wyświetlenie określonej strony sieci Web produktu.
Rysunek 1. Kategorie i produkty Makijaż struktura 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ż ASP.NET serializacji mapy lokacji w wersji 2.0 jest zbudowana na szczycie modelu dostawcy, możemy utworzyć własnego niestandardowego dostawcę mapy witryny, który pobiera dane z alternatywnego magazynu danych, takiego jak baza danych lub architektura. W tym samouczku utworzymy dostawcę niestandardowego, który pobiera dane z usługi BLL. Zacznijmy!
Uwaga
Niestandardowy dostawca mapy witryny utworzony w tym samouczku jest ściśle powiązany z architekturą aplikacji i modelem danych. Jeff Prosise s Storing Site Maps in SQL Server and The SQL Site Map Provider You ve Was Was Waiting For articles examine a generalized approach to storing site map data in SQL Server .The SQL Site Map Provider You ve Was Waiting For articles examine a generalized approach to storing site map data in SQL Server .
Krok 1. Tworzenie niestandardowych stron sieci Web dostawcy map witryn
Zanim zaczniemy tworzyć niestandardowego dostawcę mapy witryny, najpierw dodajmy strony ASP.NET, których będziemy potrzebować 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.aspx
ProductsByCategory.aspx
ProductDetails.aspx
CustomProviders
Dodaj również podfolder do App_Code
folderu .
Rysunek 2. Dodawanie stron ASP.NET dla samouczków związanych z dostawcą mapy witryny
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 buforowaniu <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
programu pośmiń chwilę, aby wyświetlić witrynę internetową samouczków za pośrednictwem przeglądarki. Menu po lewej stronie zawiera teraz element dla jedynego samouczka dostawcy mapy witryny.
Rysunek 3. Mapa witryny zawiera teraz wpis dla 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 dostawcę, który zwraca mapę witryny zawierającą węzeł główny wraz z węzłem dla każdej kategorii i produktu, jak pokazano 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 będzie ~/SiteMapProvider/Default.aspx
mieć wartość , która będzie zawierać listę wszystkich kategorii w bazie danych. Każdy węzeł kategorii na mapie witryny będzie miał adres URL wskazujący element , który będzie zawierać ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID
listę wszystkich produktów w określonym identyfikatorze categoryID. Na koniec każdy węzeł mapy witryny produktu wskaże ~/SiteMapProvider/ProductDetails.aspx?ProductID=productID
element , który wyświetli szczegóły określonego produktu.
Aby rozpocząć, musimy utworzyć Default.aspx
strony , ProductsByCategory.aspx
i ProductDetails.aspx
. Te strony są wykonywane odpowiednio w krokach 2, 3 i 4. Ponieważ wepchnięcie tego samouczka dotyczy dostawców mapy witryny, a od poprzednich samouczków omówiliśmy tworzenie tego rodzaju wielostronicowych raportów wzorcowych/szczegółowych, spieszymy się przez kroki od 2 do 4. Jeśli potrzebujesz odświeżenia podczas tworzenia raportów wzorca/szczegółów obejmujących wiele stron, zapoznaj się z samouczkiem Filtrowanie wzorca/szczegółów na dwóch stronach .
Krok 2. Wyświetlanie listy kategorii
Default.aspx
Otwórz stronę w folderze SiteMapProvider
i przeciągnij kontrolkę GridView z przybornika do projektanta, ustawiając jej ID
wartość 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 rozwijanych na kartach UPDATE, INSERT i DELETE na wartość (Brak) (Kliknij, aby wyświetlić obraz o pełnym rozmiarze)
Po ukończeniu pracy 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 i Description
i zaktualizuj CategoryName
właściwość BoundField na HeaderText
Category .
Następnie dodaj pole HyperLinkField i umieść je tak, aby było to pole z lewej strony. DataNavigateUrlFields
Ustaw właściwość na CategoryID
, a DataNavigateUrlFormatString
właściwość 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 obiektu ObjectDataSource i dostosowaniu pól kontrolki GridView znacznik 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 przedstawia Default.aspx
wyświetlanie w przeglądarce. Kliknięcie linku Wyświetl produkty kategorii spowoduje przejście do ProductsByCategory.aspx?CategoryID=categoryID
elementu , 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 tagu inteligentnego powiąż element GridView z nowym obiektem ObjectDataSource o nazwie ProductsByCategoryDataSource
. Skonfiguruj obiekt ObjectDataSource do używania ProductsBLL
metody s GetProductsByCategoryID(categoryID)
klasy i ustaw listy rozwijane na wartość (Brak) na 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 Konfigurowanie źródła danych wyświetla monit o podanie źródła parametrów dla categoryID. Ponieważ te informacje są przekazywane przez pole CategoryID
querystring, wybierz pozycję QueryString z listy rozwijanej i wprowadź ciąg CategoryID w polu tekstowym QueryStringField, jak pokazano na rysunku 9. Kliknij przycisk Zakończ, aby zakończyć kreatora.
Rysunek 9. Użyj pola querystring dla parametru CategoryID
categoryID (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, ale ProductName
pola , 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. Dodawanie pola HyperLinkField szczegółów widoku wskazującego 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 napojów. Spowoduje to wyświetlenie ProductsByCategory.aspx?CategoryID=1
nazw, cen i dostawców 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.aspx
wyświetla szczegóły wybranych produktów. Otwórz ProductDetails.aspx
element DetailsView z przybornika i przeciągnij go do projektanta. Ustaw właściwość DetailsView ID
na ProductInfo
i wyczyść jej Height
wartości właściwości i 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 ukończeniu pracy kreatora Konfigurowanie źródła danych program Visual Studio utworzy odpowiednie pola BoundFields i CheckBoxField w obszarze DetailsView dla pól danych produktu. ProductID
Usuń pola , SupplierID
i CategoryID
BoundFields i skonfiguruj pozostałe pola w miarę dopasowania. 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
elementu , w którym zostaną wyświetlone szczegóły Chai Tea (patrz Rysunek 14).
Rysunek 14. Wyświetlana jest pozycja Chai Tea s Supplier, Category, Price i Other Information (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 katalog główny, wszystkie węzły inne niż główne muszą mieć dokładnie jeden węzeł nadrzędny, a wszystkie węzły mogą mieć dowolną liczbę elementó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
, Url
i Description
, które zawierają informacje dotyczące sekcji reprezentowanej przez klasę SiteMapNode
. Istnieje również Key
właściwość, która jednoznacznie identyfikuje każdą SiteMapNode
z nich 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 na rysunku 1, ale szczegóły implementacji zostały naszkicowane bardziej szczegółowymi szczegółami.
Rysunek 15. Każda z nich SiteMapNode
ma właściwości takie jak Title
, Url
, Key
i 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ść klasy RootNode
zwraca wystąpienie główne SiteMapNode
mapy witryny. CurrentNode
Zwraca SiteMapNode
właściwość, której Url
właściwość odpowiada adresowi URL aktualnie żądanej strony. Ta klasa jest używana wewnętrznie przez kontrolki nawigacji sieci Web ASP.NET 2.0.
SiteMap
Gdy dostęp do właściwości klasy jest uzyskiwany, musi serializować strukturę mapy witryny z pewnego nośnika trwałego do pamięci. Jednak logika serializacji mapy witryny nie jest zakodowana w SiteMap
klasie. Zamiast tego w czasie wykonywania SiteMap
klasa określa, który dostawca mapy lokacji 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ę mapy witryny.
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 , które Clear()
dodają i usuwają SiteMapNode
s do wewnętrznego Hashtable
elementu . XmlSiteMapProvider
pochodzi z StaticSiteMapProvider
.
Podczas tworzenia niestandardowego dostawcy mapy witryny, który rozszerza StaticSiteMapProvider
program , istnieją dwie abstrakcyjne metody, które muszą zostać zastąpione: BuildSiteMap
i GetRootNodeCore
. BuildSiteMap
, jak wskazuje jego nazwa, jest odpowiedzialny za ładowanie struktury mapy lokacji z magazynu trwałego 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 jest rejestrowana XmlSiteMapProvider
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ści nazw i typów w kroku 7 po utworzeniu niestandardowego dostawcy mapy witryny.
Klasa dostawcy mapy witryny jest tworzone po raz pierwszy z SiteMap
klasy i pozostaje w pamięci przez cały okres istnienia 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 razie, jeśli nie buforujemy struktury mapy witryny za BuildSiteMap
każdym razem, gdy jest wywoływana, musimy ponownie pobrać informacje o produkcie i kategorii z architektury (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ć czasu lub wygaśnięcia opartego na zależnościach pamięci podręcznej SQL.
Uwaga
Dostawca mapy witryny może opcjonalnie zastąpić metodę Initialize
. Initialize
jest wywoływany po pierwszym utworzeniu wystąpienia dostawcy mapy lokacji i jest przekazywany wszelkie atrybuty niestandardowe przypisane do dostawcy w Web.config
elemecie, <add>
na przykład: <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 odczytaliśmy dane kategorii i produktów bezpośrednio z bazy danych, w przeciwieństwie do architektury, prawdopodobnie chcemy zezwolić deweloperowi strony na określenie bazy danych parametry połączenia, Web.config
zamiast używać wartości zakodowanej w kodzie dostawcy. Niestandardowy dostawca mapy witryny, który utworzymy w kroku 6, nie zastępuje tej Initialize
metody. Przykład użycia Initialize
metody można znaleźć w artykule Jeff Prosise s Storing Site Maps in SQL Server (Mapy witryn Storing w programie SQL Server ).
Krok 6. Tworzenie niestandardowego dostawcy mapy lokacji
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ą klasę StaticSiteMapProvider
. W kroku 1 poprosiłem Cię o dodanie folderu w App_Code
folderze — dodaj nową klasę CustomProviders
do tego folderu o nazwie NorthwindSiteMapProvider
. Dodaj następujący kod do NorthwindSiteMapProvider
klasy:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.Caching;
public class NorthwindSiteMapProvider : StaticSiteMapProvider
{
private readonly object siteMapLock = new object();
private SiteMapNode root = null;
public const string CacheDependencyKey =
"NorthwindSiteMapProviderCacheDependency";
public override SiteMapNode BuildSiteMap()
{
// Use a lock to make this method thread-safe
lock (siteMapLock)
{
// First, see if we already have constructed the
// rootNode. If so, return it...
if (root != null)
return root;
// We need to build the site map!
// Clear out the current site map structure
base.Clear();
// Get the categories and products information from the database
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = productsAPI.GetProducts();
// Create the root SiteMapNode
root = new SiteMapNode(
this, "root", "~/SiteMapProvider/Default.aspx", "All Categories");
AddNode(root);
// Create SiteMapNodes for the categories and products
foreach (Northwind.ProductsRow product in products)
{
// Add a new category SiteMapNode, if needed
string categoryKey, categoryName;
bool createUrlForCategoryNode = true;
if (product.IsCategoryIDNull())
{
categoryKey = "Category:None";
categoryName = "None";
createUrlForCategoryNode = false;
}
else
{
categoryKey = string.Concat("Category:", product.CategoryID);
categoryName = product.CategoryName;
}
SiteMapNode categoryNode = FindSiteMapNodeFromKey(categoryKey);
// Add the category SiteMapNode if it does not exist
if (categoryNode == null)
{
string productsByCategoryUrl = string.Empty;
if (createUrlForCategoryNode)
productsByCategoryUrl =
"~/SiteMapProvider/ProductsByCategory.aspx?CategoryID="
+ product.CategoryID;
categoryNode = new SiteMapNode(
this, categoryKey, productsByCategoryUrl, categoryName);
AddNode(categoryNode, root);
}
// Add the product SiteMapNode
string productUrl =
"~/SiteMapProvider/ProductDetails.aspx?ProductID="
+ product.ProductID;
SiteMapNode productNode = new SiteMapNode(
this, string.Concat("Product:", product.ProductID),
productUrl, product.ProductName);
AddNode(productNode, categoryNode);
}
// Add a "dummy" item to the cache using a SqlCacheDependency
// on the Products and Categories tables
System.Web.Caching.SqlCacheDependency productsTableDependency =
new System.Web.Caching.SqlCacheDependency("NorthwindDB", "Products");
System.Web.Caching.SqlCacheDependency categoriesTableDependency =
new System.Web.Caching.SqlCacheDependency("NorthwindDB", "Categories");
// Create an AggregateCacheDependency
System.Web.Caching.AggregateCacheDependency aggregateDependencies =
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,
new CacheItemRemovedCallback(OnSiteMapChanged));
// Finally, return the root node
return root;
}
}
protected override SiteMapNode GetRootNodeCore()
{
return BuildSiteMap();
}
protected void OnSiteMapChanged(string key, object value, CacheItemRemovedReason reason)
{
lock (siteMapLock)
{
if (string.Compare(key, CacheDependencyKey) == 0)
{
// Refresh the site map
root = null;
}
}
}
public DateTime? CachedDate
{
get
{
return HttpRuntime.Cache[CacheDependencyKey] as DateTime?;
}
}
}
Zacznijmy od eksplorowania tej metody klasyBuildSiteMap
, która zaczyna się od instrukcjilock
. Instrukcja lock
umożliwia wprowadzanie tylko jednego wątku, a tym samym serializowanie dostępu do kodu i zapobieganie przechodzeniu dwóch współbieżnych wątków na siebie nawzajem.
Zmienna root
na poziomie SiteMapNode
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 null
utworzona struktura mapy lokacji. Węzeł główny mapy lokacji jest przypisywany do root
podczas procesu budowy, root
tak aby przy następnym wywołaniu tej metody nie będzie .null
W związku z tym tak długo, jak root
nie null
jest struktura mapy witryny zostanie zwrócona do obiektu wywołującego bez konieczności jego ponownego tworzenia.
Jeśli katalog główny to null
, struktura mapy witryny jest tworzona na podstawie informacji o produkcie i kategorii. Mapa lokacji jest tworzona przez utworzenie SiteMapNode
wystąpień, a następnie utworzenie hierarchii za pomocą wywołań StaticSiteMapProvider
metody klasy s AddNode
. AddNode
wykonuje wewnętrzne księgowanie, przechowując wystąpienia assortowane SiteMapNode
w obiekcie Hashtable
. Zanim zaczniemy konstruować hierarchię, zaczynamy od wywołania Clear
metody , która czyści elementy z wewnętrznej Hashtable
klasy . ProductsBLL
Następnie metoda s GetProducts
klasy i wynikowe ProductsDataTable
są przechowywane w zmiennych lokalnych.
Budowa mapy lokacji rozpoczyna się od utworzenia węzła głównego i przypisania go do root
elementu . Przeciążenie konstruktora używanego SiteMapNode
tutaj i w tym BuildSiteMap
miejscu jest przekazywane następujące informacje:
- Odwołanie do dostawcy mapy witryny (
this
). Key
SSiteMapNode
. Ta wymagana wartość musi być unikatowa dla każdegoSiteMapNode
elementu .Url
SSiteMapNode
.Url
wartość jest opcjonalna, ale jeśli jest podana, każdaSiteMapNode
wartość sUrl
musi być unikatowa.- Parametr
SiteMapNode
sTitle
, który jest wymagany.
Wywołanie AddNode(root)
metody dodaje SiteMapNode
root
element do mapy witryny jako katalog główny. Następnie każda ProductRow
z nich jest ProductsDataTable
wyliczana. Jeśli dla bieżącej kategorii produktu istnieje już element , SiteMapNode
zostanie on przywołyny. W przeciwnym razie zostanie utworzony nowy SiteMapNode
element kategorii i dodany jako element podrzędny SiteMapNode``root
metody za pomocą wywołania AddNode(categoryNode, root)
metody. 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 , gdy właściwość produktu Url
SiteMapNode
jest przypisana ~/SiteMapNode/ProductDetails.aspx?ProductID=productID
.~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID
Url
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
pusty ciąg, ponieważ ProductBLL
metoda klasy s GetProductsByCategory(categoryID)
obecnie nie ma możliwości zwrócenia tylko tych produktów z wartością NULL
CategoryID
. Chcę również zademonstrować, w jaki sposób kontrolki nawigacji renderują element SiteMapNode
, który nie ma wartości dla jej Url
właściwości. Zachęcam do rozszerzenia tego samouczka, aby właściwość None SiteMapNode
Url
wskazuje na ProductsByCategory.aspx
, ale wyświetla tylko produkty z wartościami NULL
CategoryID
.
Po utworzeniu mapy witryny do pamięci podręcznej danych jest dodawany dowolny obiekt przy użyciu zależności Categories
pamięci podręcznej SQL dla tabel i Products
za pośrednictwem AggregateCacheDependency
obiektu . 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 lokacji używa jednak przeciążenia metody pamięci podręcznej Insert
danych, którą jeszcze eksplorowaliś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 root
na 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
przywraca wartość root
, null
gdy element pamięci podręcznej zostanie usunięty. Po ponownym ustawieniu elementu głównego na null
element zostanie wywołany element , przy następnym BuildSiteMap
wywołaniu 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 NorthwindSiteMapProvider
w kroku 6, musimy zarejestrować ją w <siteMap>
sekcji .Web.config
W szczególności dodaj następujący znacznik w elemecie w pliku <system.web>
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; drugi 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
programu pośmiń chwilę, aby 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 korzystającego z NorthwindSiteMapProvider
elementu , należy jawnie określić, że należy 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
programie możemy dodać kontrolki nawigacji do Default.aspx
strony , 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 adres nadrzędny wskazujący bieżącą lokalizację strony w mapie witryny. Dodaliśmy ścieżkę SiteMapPath w górnej części strony wzorcowej z powrotem w samouczku Strony wzorcowe i Nawigacja witryny.
Pośmiń chwilę, aby wyświetlić tę stronę za pośrednictwem przeglądarki. Ścieżka SiteMapPath dodana na rysunku 16 używa domyślnego dostawcy mapy witryny, ściągając dane z programu Web.sitemap
. W związku z tym linki do stron nadrzędnych zawierają stronę Home > Customizing the Site Map (Dostosowywanie mapy witryny), podobnie jak w przypadku stron nadrzędnych w prawym górnym rogu.
Rysunek 17. Link do stron nadrzędnych używa domyślnego dostawcy mapy witryny (kliknij, aby wyświetlić obraz pełnowymiarowy)
Aby obiekt SiteMapPath został dodany na rysunku 16, użyj niestandardowego dostawcy mapy witryny utworzonego w kroku 6, ustaw jej SiteMapProvider
właściwość na Northwind, nazwę przypisaną NorthwindSiteMapProvider
do elementu w Web.config
pliku . Niestety projektant nadal używa domyślnego dostawcy mapy witryny, ale jeśli odwiedzasz stronę za pośrednictwem przeglądarki po wprowadzeniu tej zmiany właściwości, zobaczysz, że strona do stron nadrzędnych używa teraz niestandardowego dostawcy mapy witryny.
Rysunek 18. Link do stron nadrzędnych używa teraz niestandardowego dostawcy NorthwindSiteMapProvider
mapy witryny (kliknij, aby wyświetlić obraz pełnowymiarowy)
Kontrolka SiteMapPath wyświetla bardziej funkcjonalny interfejs użytkownika na ProductsByCategory.aspx
stronach i ProductDetails.aspx
. Dodaj ścieżkę SiteMapPath do tych stron, ustawiając SiteMapProvider
właściwość w obu elementach na Northwind. Kliknij Default.aspx
link Wyświetl produkty dla napojów, a następnie na link Wyświetl szczegóły dla Herbaty Chai. Jak pokazano na rysunku 19, strona do stron nadrzędnych zawiera bieżącą sekcję mapy witryny (Chai Tea) i jej przodków: Napoje i Wszystkie kategorie .
Rysunek 19. Link do stron nadrzędnych używa teraz niestandardowego dostawcy NorthwindSiteMapProvider
mapy witryny (kliknij, aby wyświetlić obraz pełnowymiarowy)
Inne elementy interfejsu użytkownika nawigacji mogą być używane oprócz kontrolki SiteMapPath, takich jak Menu i TreeView. ProductsByCategory.aspx
Strony Default.aspx
, i ProductDetails.aspx
w pobranym pliku na potrzeby tego samouczka, na przykład wszystkie kontrolki menu dołączania (zobacz Rysunek 20). Zobacz ASP.NET zaawansowane funkcje nawigacji witryny w wersji 2.0 oraz sekcję Using Site Navigation Controls (Używanie kontrolek nawigacji lokacji) w przewodnikach Szybki start ASP.NET 2.0, aby uzyskać bardziej szczegółowe informacje na temat kontrolek nawigacji i systemu mapy lokacji 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 katalog główny SiteMapNode
domyślnego dostawcy:
SiteMapNode root = 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:
SiteMapNode root = SiteMap.Providers["name"].RootNode;
Gdzie nazwa to nazwa niestandardowego dostawcy mapy witryny ( Northwind, dla naszej aplikacji internetowej).
Aby uzyskać dostęp do elementu członkowskiego specyficznego dla dostawcy mapy lokacji, użyj polecenia SiteMap.Providers["name"]
, aby pobrać wystąpienie dostawcy, a następnie rzutować go do odpowiedniego typu. Aby na przykład wyświetlić NorthwindSiteMapProvider
właściwość s CachedDate
na stronie ASP.NET, użyj następującego kodu:
NorthwindSiteMapProvider customProvider =
SiteMap.Providers["Northwind"] as NorthwindSiteMapProvider;
if (customProvider != null)
{
DateTime? lastCachedDate = customProvider.CachedDate;
if (lastCachedDate != null)
LabelID.Text = "Site map cached on: " + lastCachedDate.Value.ToString();
else
LabelID.Text = "The site map is being reconstructed!";
}
Uwaga
Pamiętaj, aby przetestować funkcję zależności pamięci podręcznej SQL. Po przejściu Default.aspx
na strony , ProductsByCategory.aspx
i ProductDetails.aspx
przejdź do jednego z samouczków w sekcji Edytowanie, wstawianie i usuwanie oraz 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 nawigacji sieci Web oraz domyślnego dostawcę mapy witryny, który oczekuje, że informacje o mapie witryny 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 pokazano, jak utworzyć niestandardowego dostawcę mapy witryny opartego na mapie witryny na podstawie informacji o produkcie i kategorii uszczepionych z architektury aplikacji. Nasz dostawca rozszerzył klasę StaticSiteMapProvider
i wiązał się z utworzeniem BuildSiteMap
metody, która pobierała dane, konstruowała hierarchię mapy lokacji i 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 dostawcy mapy lokacji SQL, na który 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 24 godzinach. Można go uzyskać pod adresem mitchell@4GuysFromRolla.com. lub za pośrednictwem swojego bloga, który można znaleźć na stronie http://ScottOnWriting.NET.
Specjalne podziękowania
Ta seria samouczków została omówiona przez wielu przydatnych recenzentów. Recenzenci w tym samouczku to Dave Gardner, Zack Jones, Teresa Murphy i Bernadette Leigh. Chcesz przejrzeć nadchodzące artykuły MSDN? Jeśli tak, upuść mi wiersz pod adresem mitchell@4GuysFromRolla.com.