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. Dostawca oparty na formacie XML jest odpowiedni dla wielu małych i średnich witryn sieci Web, ale większe aplikacje sieci Web wymagają bardziej dynamicznej mapy witryny. W tym samouczku utworzymy niestandardowego dostawcę mapy lokacji, który pobiera dane z warstwy logiki biznesowej, który z kolei pobiera dane z bazy danych.
Wprowadzenie
funkcja mapy witryny w wersji 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 dane mapy witryny można uzyskać dostęp programowo za pośrednictwem klasy w System.Web
przestrzeni nazw lub za pomocą SiteMap
różnych kontrolek nawigacji w 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 programem ASP.NET 2.0 utrwala strukturę mapy witryny w pliku XML. W samouczku dotyczącym stron wzorcowych i nawigacji po witrynie 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 oparty na formacie XML sprawdza się, jeśli struktura mapy witryny jest dość statyczna, na przykład w przypadku tych samouczków. Jednak w wielu scenariuszach potrzebna jest bardziej dynamiczna mapa lokacji. Rozważ mapę witryny pokazaną na rysunku 1, w której każda kategoria i produkt są wyświetlane jako sekcje w strukturze witryny internetowej. Na tej mapie witryny odwiedzanie strony internetowej odpowiadającej węzłowi głównemu może zawierać 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 spowoduje wyświetlenie tych szczegółów produktu.
Rysunek 1. Kategorie i produkty makijaż struktury mapy witryny (kliknij, aby wyświetlić obraz pełnowymiarowy)
Chociaż ta struktura oparta na kategorii i produktach może być trwale zakodowana w Web.sitemap
pliku, plik musi zostać zaktualizowany za każdym razem, gdy kategoria lub produkt został dodany, usunięty lub zmieniono jego nazwę. W związku z tym konserwacja mapy witryny byłaby znacznie uproszczona, jeśli jej struktura została pobrana z bazy danych lub, w idealnym przypadku, z warstwy logiki biznesowej architektury aplikacji. Dzięki temu w miarę dodawania produktów i kategorii, zmieniania ich nazwy lub usuwania mapa witryny zostanie automatycznie zaktualizowana, aby odzwierciedlić te zmiany.
Ponieważ ASP.NET serializacji mapy lokacji w wersji 2.0 jest tworzona 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 storing Site Maps in SQL Server and The SQL Site Map Provider You been Waiting For articles examine a generalized approach to storing site map data in SQL Server .The SQL Site Map Provider You BeenAiting For articles examine a generalized approach to storing site map data in SQL Server (Przechowywanie map witryn w SQL Server).
Krok 1. Tworzenie niestandardowych stron sieci Web dostawcy map witryn
Przed rozpoczęciem tworzenia niestandardowego dostawcy 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 do tego folderu następujące strony ASP.NET, 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 mapy witryny Provider-Related Samouczki
Ponieważ w tej sekcji jest 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 Web.sitemap
element , aby uwzględnić odwołanie do Default.aspx
strony. W szczególności dodaj następujące znaczniki 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święć 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. W przypadku mapy naszej 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ślonej kategoriiID. 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ż ten samouczek jest oparty na dostawcach mapy witryny, a od poprzednich samouczków omówiliśmy tworzenie tego rodzaju wielostronicowych raportów wzorcowych/szczegółowych, pospieszniemy 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 Projektant, ustawiając jej ID
wartość na Categories
. Z tagu inteligentnego GridView powiąż go z nową wartością ObjectDataSource o nazwie CategoriesDataSource
i skonfiguruj ją tak, aby pobierała dane przy użyciu CategoriesBLL
metody klasy s GetCategories
. Ponieważ ten obiekt 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 Drop-Down Listy na kartach UPDATE, INSERT i DELETE na wartość (Brak) (kliknij, aby wyświetlić obraz w pełnym rozmiarze)
Po zakończeniu pracy kreatora Konfigurowanie źródła danych program Visual Studio doda pole BoundField dla CategoryID
, , Description
CategoryName
, NumberOfProducts
i BrochurePath
. Zmodyfikuj obiekt GridView, tak aby zawierał tylko pola CategoryName
i i Description
i zaktualizuj CategoryName
właściwość BoundField HeaderText
do właściwości Category .
Następnie dodaj pole HyperLinkField i umieść je tak, aby było to pole najbardziej po lewej stronie. 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 obiektu HyperLinkField do kontrolki Categories
GridView
Po utworzeniu obiektu ObjectDataSource i dostosowaniu pól kontrolki GridView znacznik deklaratywny będzie 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
widok 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 kreatora 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 ProductName
oprócz pól , UnitPrice
i SupplierName
BoundFields. Dostosuj te trzy właściwości BoundFields HeaderText
, aby odpowiednio odczytywać pozycje Product (Produkt), Price (Cena) i Supplier (Dostawca). Sformatuj pole UnitPrice
Powiązane jako walutę.
Następnie dodaj wartość HyperLinkField i przenieś ją do lewej pozycji. Ustaw jej Text
właściwość na View Details, jej DataNavigateUrlFields
właściwość na ProductID
, a jej DataNavigateUrlFormatString
właściwość na ~/SiteMapProvider/ProductDetails.aspx?ProductID={0}
.
Rysunek 10. Dodawanie pola hiperlinkowego widoku wskazującego 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 ProductsByCategory.aspx?CategoryID=1
to wyświetlenie 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
i przeciągnij element DetailsView z przybornika do Projektant. Ustaw właściwość Kontrolka ID
DetailsView na ProductInfo
i wyczyść jej Height
wartości właściwości i Width
. Z tagu inteligentnego powiąż element DetailsView z nową klasą ObjectDataSource o nazwie ProductDataSource
, konfigurując element ObjectDataSource w celu ściągnięcia danych z ProductsBLL
metody klasy s GetProductByProductID(productID)
. Podobnie jak w przypadku poprzednich stron sieci Web 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 w 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 są przekazywane przez pole ProductID
querystring, ustaw listę rozwijaną na QueryString i pole tekstowe QueryStringField na ProductID. Na koniec kliknij przycisk Zakończ, aby zakończyć pracę kreatora.
Rysunek 13. Konfigurowanie parametru productID w celu ściągnięcia jego wartości z ProductID
pola querystring (kliknij, aby wyświetlić obraz pełnowymiarowy)
Po zakończeniu pracy kreatora Konfigurowanie źródła danych program Visual Studio utworzy odpowiednie pola BoundFields i Pole CheckBoxField w obszarze DetailsView dla pól danych produktu. ProductID
Usuń pola , SupplierID
i CategoryID
BoundFields i skonfiguruj pozostałe pola zgodnie z potrzebami. Po kilku konfiguracjach estetycznych znaczniki deklaratywne obiektów 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
obiektu , w którym zostaną wyświetlone szczegóły Chai Tea (patrz Rysunek 14).
Rysunek 14. Chai Tea s Supplier, Category, Price i Other Information is Displayed (Kliknij, aby wyświetlić pełny obraz)
Krok 5. Opis wewnętrznych funkcji 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 sieci Web. Te sekcje często mają odpowiednią stronę internetową. W związku z tym SiteMapNode
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 z 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 sieci Web nawigacji ASP.NET 2.0.
SiteMap
Po korzystaniu z właściwości klasy należy serializować strukturę mapy lokacji 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 jest używana klasa,XmlSiteMapProvider
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 mapy witryny muszą pochodzić z SiteMapProvider
klasy , która zawiera podstawowe metody i właściwości potrzebne dla dostawców mapy witryny, 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
obiekty do wewnętrznego Hashtable
obiektu . XmlSiteMapProvider
pochodzi z .StaticSiteMapProvider
Podczas tworzenia niestandardowego dostawcy mapy witryny, który rozszerza StaticSiteMapProvider
usługę , istnieją dwie metody abstrakcyjne, które muszą zostać zastąpione: BuildSiteMap
i GetRootNodeCore
. BuildSiteMap
, jak wskazuje jej 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 mapy witryny, dodaj następujące znaczniki do :Web.config
<configuration>
<system.web>
...
<siteMap defaultProvider="defaultProviderName">
<providers>
<add name="name" type="type" />
</providers>
</siteMap>
</system.web>
</configuration>
Wartość nazwy przypisuje nazwę czytelną dla człowieka do dostawcy, podczas gdy typ określa w pełni kwalifikowaną nazwę typu dostawcy mapy witryny. Zapoznamy się z konkretnymi wartościami nazw i typów w kroku 7 po utworzeniu niestandardowego dostawcy mapy witryny.
Klasa dostawcy mapy witryny jest tworzone przy pierwszym uzyskiwaniu dostępu 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ę sieci Web, konieczne jest, aby metody dostawcy były bezpieczne wątkowo.
Ze względu na wydajność i skalowalność ważne jest buforowanie struktury mapy lokacji w pamięci i zwracanie tej buforowanej struktury zamiast ponownego tworzenia jej za każdym razem, gdy BuildSiteMap
metoda jest wywoływana. BuildSiteMap
W zależności od kontrolek nawigacji używanych na stronie na stronie i głębokości struktury mapy witryny może być wywoływana kilka razy na żądanie strony. W każdym razie, jeśli nie będziemy buforować struktury mapy witryny za BuildSiteMap
każdym razem, gdy jest wywoływany, musimy ponownie pobrać informacje o produkcie i kategorii z architektury (co spowodowałoby zapytanie do bazy danych). Jak omówiono w poprzednich samouczkach dotyczących buforowania, buforowane dane mogą stać się nieaktualne. Aby temu zastosować, możemy użyć czasu lub wygaśnięcia opartych 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 witryny i jest przekazywany wszystkie 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 pozwolić deweloperowi strony określić bazę danych parametry połączenia Web.config
zamiast używać zakodowanej wartości 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 w SQL Server artykule.
Krok 6. Tworzenie niestandardowego dostawcy mapy witryny
Aby utworzyć niestandardowego dostawcę mapy witryny, który kompiluje mapę witryny na podstawie 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 folderze App_Code
— 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 naraz, 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. Gdy mapa witryny jest tworzona po raz pierwszy lub po raz pierwszy po zmodyfikowaniu danych bazowych, root
zostanie null
utworzona, a struktura mapy lokacji zostanie utworzona. Węzeł główny mapy lokacji jest przypisywany do root
podczas procesu budowy, tak aby przy następnym wywołaniu root
tej metody nie będzie .null
W związku z tym tak długo, jak root
nie null
jest struktura mapy lokacji zostanie zwrócona do obiektu wywołującego bez konieczności jego ponownego tworzenia.
Jeśli element główny to null
, struktura mapy witryny jest tworzona na podstawie informacji o produkcie i kategorii. Mapa witryny 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
. Przed rozpoczęciem konstruowania hierarchii zaczniemy 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żytegoSiteMapNode
w tym miejscu 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 zostanie podana, każdaSiteMapNode
wartość musi być unikatowaUrl
.- Parametr
SiteMapNode
sTitle
, który jest wymagany.
Wywołanie AddNode(root)
metody dodaje element SiteMapNode
root
do mapy witryny jako element główny. Następnie każda ProductRow
z nich ProductsDataTable
jest wyliczana. Jeśli dla bieżącej kategorii produktu istnieje SiteMapNode
już element , zostanie przywołyny. W przeciwnym razie zostanie utworzony nowy SiteMapNode
element dla kategorii i dodany jako element podrzędny SiteMapNode``root
metody za pośrednictwem wywołania AddNode(categoryNode, root)
metody. Po znalezieniu lub utworzeniu SiteMapNode
odpowiedniego węzła kategorii SiteMapNode
tworzony jest element dla bieżącego produktu i dodawany jako element podrzędny kategorii SiteMapNode
za pośrednictwem elementu AddNode(productNode, categoryNode)
. Należy pamiętać, że wartość właściwości kategorii SiteMapNode
jest, 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ść ma wartość 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 obecnie GetProductsByCategory(categoryID)
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 tak, aby właściwość None SiteMapNode
wskazuje na ProductsByCategory.aspx
, ale wyświetla tylko produkty z wartościamiNULL
CategoryID
.Url
Po utworzeniu mapy lokacji dowolny obiekt jest dodawany do pamięci podręcznej danych przy użyciu zależności pamięci podręcznej SQL od Categories
tabel i Products
za pośrednictwem AggregateCacheDependency
obiektu. Zapoznaliśmy się z użyciem zależności pamięci podręcznej SQL w poprzednim samouczku przy użyciu 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 delegat, 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 OnSiteMapChanged
metodę zdefiniowaną dalej w dół w NorthwindSiteMapProvider
klasie.
Uwaga
Reprezentacja mapy lokacji w pamięci jest buforowana za pośrednictwem 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 między wszystkimi wątkami 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
się zmieniają. 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 użytkownika. Metoda OnSiteMapChanged
jest ustawiana root
z powrotem do null
momentu usunięcia elementu pamięci podręcznej. Po ponownym ustawieniu elementu głównego na null
wartość , przy następnym BuildSiteMap
wywołaniu struktura mapy witryny zostanie ponownie skompilowana. CachedDate
Na koniec właściwość zwraca wartość daty i godziny przechowywanej w pamięci podręcznej danych, jeśli taka wartość istnieje. Ta właściwość może służyć deweloperowi strony do 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ące znaczniki w elemecie <system.web>
w pliku Web.config
:
<siteMap defaultProvider="AspNetXmlSiteMapProvider">
<providers>
<add name="Northwind" type="NorthwindSiteMapProvider" />
</providers>
</siteMap>
Ta adiustacja wykonuje dwie czynności: najpierw wskazuje, że wbudowany AspNetXmlSiteMapProvider
jest domyślnym dostawcą mapy lokacji; po drugie rejestruje niestandardowego dostawcę mapy witryny utworzonego w kroku 6 z przyjazną dla człowieka nazwą Northwind.
Uwaga
W przypadku dostawców map lokacji znajdujących się w folderze aplikacji App_Code
wartość atrybutu type
to po prostu nazwa 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ść atrybutu type
będzie przestrzeń nazw.ClassName, AssemblyName .
Po zaktualizowaniu Web.config
programu poświęć 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
. Dzieje się tak, ponieważ pozostawiliśmy AspNetXmlSiteMapProvider
jako dostawcę domyślnego. Aby utworzyć element interfejsu użytkownika nawigacji korzystającego z elementu NorthwindSiteMapProvider
, 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 lokacji
Za pomocą niestandardowego dostawcy mapy witryny utworzonego i zarejestrowanego w Web.config
programie możemy dodać kontrolki nawigacji do Default.aspx
plików , ProductsByCategory.aspx
i ProductDetails.aspx
stron w folderze SiteMapProvider
. Zacznij od otwarcia Default.aspx
strony i przeciągnij element SiteMapPath
z przybornika do Projektant. Kontrolka SiteMapPath znajduje się w sekcji Nawigacja przybornika.
Rysunek 16. Dodawanie ścieżki SiteMapPath do Default.aspx
(kliknij, aby wyświetlić obraz pełnowymiarowy)
Kontrolka SiteMapPath wyświetla link do stron nadrzędnych wskazujący bieżącą lokalizację strony na mapie witryny. Dodaliśmy ścieżkę SiteMapPath w górnej części strony wzorcowej z powrotem w samouczku Strony wzorcowe i Nawigacja po witrynie .
Poświęć 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 Web.sitemap
elementu . W związku z tym w witrynie nadrzędnym jest wyświetlana > strona główna Dostosowywanie mapy witryny, podobnie jak strona do stron nadrzędnych w prawym górnym rogu.
Rysunek 17. Strona 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ą do NorthwindSiteMapProvider
elementu w Web.config
. 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. Strona do stron nadrzędnych używa teraz niestandardowego dostawcy NorthwindSiteMapProvider
mapy lokacji (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 polach na Northwind. Kliknij Default.aspx
link Wyświetl produkty dla napojów, a następnie na linku Wyświetl szczegóły dla Chai Tea. 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. Strona 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 można używać oprócz kontrolki SiteMapPath, takich jak kontrolki Menu i TreeView. Strony Default.aspx
, ProductsByCategory.aspx
i ProductDetails.aspx
w pobieraniu dla tego samouczka, na przykład wszystkie kontrolki menu dołączania (zobacz Rysunek 20). Zobacz ASP.NET 2.0 zaawansowane funkcje nawigacji witryny i sekcję Using Site Navigation Controls (Korzystanie z kontrolek nawigacji witryny ) ASP.NET 2.0 Szybki start , aby uzyskać bardziej szczegółowe informacje na temat kontrolek nawigacji i systemu mapy lokacji w ASP.NET 2.0.
Rysunek 20. Kontrolka menu Listy Każdy z kategorii i produktów (kliknij, aby wyświetlić obraz pełnowymiarowy)
Jak wspomniano wcześniej w tym samouczku, struktura mapy witryny może być uzyskiwana 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 lokacji innego niż domyślny, 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ę bazowej bazy danych, mapa lokacji powinna zostać zaktualizowana w celu wyświetlenia nowej nazwy produktu lub kategorii.
Podsumowanie
ASP.NET funkcji mapy witryny w wersji 2.0 obejmuje klasę SiteMap
, szereg wbudowanych kontrolek sieci Web nawigacji oraz domyślnego dostawcę mapy witryny, który oczekuje, że informacje o mapie witryny zostaną utrwalone w pliku XML. Aby użyć informacji o mapie witryny z innego źródła, takiego jak baza danych, architektura aplikacji lub zdalna usługa sieci Web, musimy utworzyć niestandardowego dostawcę mapy lokacji. Obejmuje to utworzenie klasy, która pochodzi bezpośrednio lub pośrednio z SiteMapProvider
klasy.
W tym samouczku pokazano, jak utworzyć niestandardowego dostawcę mapy lokacji, który na podstawie mapy witryny na podstawie informacji o produkcie i kategorii uszczelił 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ć strukturę buforowaną po zmodyfikowaniu 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 SQL Server i dostawcy mapy lokacji SQL, na który czekano
- Zestaw narzędzi dostawcy
- zaawansowane funkcje nawigacji witryny 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 do niego dotrzeć 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 sprawdzona przez wielu pomocnych recenzentów. Recenzenci na potrzeby tego samouczka 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.
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla