Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Il provider predefinito della mappa del sito in ASP.NET 2.0 recupera i dati da un file XML statico. Anche se il provider basato su XML è adatto a molti siti Web di piccole e medie dimensioni, le applicazioni Web di grandi dimensioni richiedono una mappa del sito più dinamica. In questa esercitazione verrà creato un provider di mappe del sito personalizzato che recupera i dati dal livello di logica di business, che a sua volta recupera i dati dal database.
Introduzione
ASP.NET funzionalità mappa del sito di 2.0 consente a uno sviluppatore di pagine di definire una mappa del sito dell'applicazione Web in un supporto persistente, ad esempio in un file XML. Una volta definiti, è possibile accedere ai dati della mappa del sito a livello di codice tramite la SiteMap classe nello System.Web spazio dei nomi o tramite un'ampia gamma di controlli Web di spostamento, ad esempio i controlli SiteMapPath, Menu e TreeView. Il sistema mappa del sito usa il modello di provider in modo che sia possibile creare e collegare diverse implementazioni di serializzazione della mappa del sito a un'applicazione Web. Il provider predefinito della mappa del sito fornito con ASP.NET 2.0 rende persistente la struttura della mappa del sito in un file XML. Tornare all'esercitazione Pagine master e navigazione sito è stato creato un file denominato Web.sitemap che conteneva questa struttura e che ha aggiornato il codice XML con ogni nuova sezione dell'esercitazione.
Il provider predefinito della mappa del sito basato su XML funziona correttamente se la struttura della mappa del sito è piuttosto statica, ad esempio per queste esercitazioni. In molti scenari, tuttavia, è necessaria una mappa del sito più dinamica. Si consideri la mappa del sito illustrata nella figura 1, in cui ogni categoria e prodotto vengono visualizzati come sezioni nella struttura del sito Web. Con questa mappa del sito, visitare la pagina Web corrispondente al nodo radice potrebbe elencare tutte le categorie, mentre visitando una determinata pagina Web di una categoria specifica elencare i prodotti della categoria e visualizzando una determinata pagina Web del prodotto mostrerebbe i dettagli del prodotto.
Figura 1: Categorie e prodotti trucco struttura della mappa del sito (fare clic per visualizzare l'immagine a dimensione intera)
Anche se questa struttura basata su categoria e prodotto potrebbe essere hardcoded nel Web.sitemap file, il file dovrà essere aggiornato ogni volta che una categoria o un prodotto è stato aggiunto, rimosso o rinominato. Di conseguenza, la manutenzione della mappa del sito sarebbe notevolmente semplificata se la relativa struttura è stata recuperata dal database o, idealmente, dal livello della logica di business dell'architettura dell'applicazione. In questo modo, man mano che i prodotti e le categorie sono stati aggiunti, rinominati o eliminati, la mappa del sito viene aggiornata automaticamente per riflettere queste modifiche.
Poiché ASP.NET serializzazione della mappa del sito di 2.0 s viene creata in cima al modello di provider, è possibile creare il proprio provider di mappe del sito personalizzato che recupera i dati da un archivio dati alternativo, ad esempio il database o l'architettura. In questa esercitazione verrà creato un provider personalizzato che recupera i dati dal BLL. Iniziamo!
Nota
Il provider di mappe del sito personalizzato creato in questa esercitazione è strettamente associato all'architettura e al modello di dati dell'applicazione. Jeff Prosise archivia mappe del sito in SQL Server e il provider di mappe del sito SQL in attesa di articoli esaminano un approccio generalizzato all'archiviazione dei dati della mappa del sito in SQL Server.
Passaggio 1: Creazione delle pagine Web del provider di mappe siti personalizzato
Prima di iniziare a creare un provider di mappe del sito personalizzato, aggiungere prima le pagine di ASP.NET necessarie per questa esercitazione. Per iniziare, aggiungere una nuova cartella denominata SiteMapProvider. Aggiungere quindi le pagine di ASP.NET seguenti a tale cartella, assicurandosi di associare ogni pagina alla Site.master pagina master:
Default.aspxProductsByCategory.aspxProductDetails.aspx
Aggiungere anche una CustomProviders sottocartella alla App_Code cartella .
Figura 2: Aggiungere le pagine ASP.NET per le esercitazioni correlate al provider della mappa del sito
Poiché è disponibile una sola esercitazione per questa sezione, non è necessario Default.aspx elencare le esercitazioni della sezione. Verranno invece Default.aspx visualizzate le categorie in un controllo GridView. Questo argomento verrà affrontato nel passaggio 2.
Aggiornare Web.sitemap quindi per includere un riferimento alla Default.aspx pagina. In particolare, aggiungere il markup seguente dopo la memorizzazione nella cache <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." />
Dopo l'aggiornamento Web.sitemap, dedicare qualche minuto per visualizzare il sito Web delle esercitazioni tramite un browser. Il menu a sinistra include ora una voce per l'unica esercitazione sul provider di mappe del sito.
Figura 3: La mappa del sito include ora una voce per l'esercitazione sul provider di mappe del sito
Questa esercitazione è incentrata principalmente sulla creazione di un provider di mappe del sito personalizzato e sulla configurazione di un'applicazione Web per l'uso di tale provider. In particolare, verrà creato un provider che restituisce una mappa del sito che include un nodo radice insieme a un nodo per ogni categoria e prodotto, come illustrato nella figura 1. In generale, ogni nodo della mappa del sito può specificare un URL. Per la mappa del sito, l'URL del nodo radice sarà ~/SiteMapProvider/Default.aspx, che elenca tutte le categorie nel database. Ogni nodo di categoria nella mappa del sito avrà un URL che punta a ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID, che elenca tutti i prodotti nell'ID categoria specificato. Infine, ogni nodo della mappa del sito prodotto punterà a ~/SiteMapProvider/ProductDetails.aspx?ProductID=productID, che visualizzerà i dettagli specifici del prodotto.
Per iniziare, è necessario creare le Default.aspxpagine , ProductsByCategory.aspxe ProductDetails.aspx . Queste pagine vengono completate rispettivamente nei passaggi 2, 3 e 4. Poiché la spinta di questa esercitazione è sui provider di mappe del sito, e dal momento che le esercitazioni precedenti hanno illustrato la creazione di questi tipi di report master/dettagli multi-pagina, si farà fretta nei passaggi da 2 a 4. Se è necessario un aggiornamento per la creazione di report master/dettagli che si estendono su più pagine, fare riferimento all'esercitazione Filtro master/dettagli su due pagine .
Passaggio 2: Visualizzazione di un elenco di categorie
Aprire la Default.aspx pagina nella SiteMapProvider cartella e trascinare gridView dalla casella degli strumenti nella finestra di progettazione, impostandone su IDCategories. Dallo smart tag gridView, associarlo a un nuovo ObjectDataSource denominato CategoriesDataSource e configurarlo in modo che recuperi i dati usando il CategoriesBLL metodo della classe s GetCategories . Poiché gridView visualizza solo le categorie e non fornisce funzionalità di modifica dei dati, impostare gli elenchi a discesa nelle schede UPDATE, INSERT e DELETE su (Nessuno).
Figura 4: Configurare ObjectDataSource per restituire categorie usando il metodo (GetCategories a dimensione intera)
Figura 5: Impostare gli elenchi a discesa nelle schede UPDATE, INSERT e DELETE su (Nessuno) (Fare clic per visualizzare l'immagine a dimensione intera)
Dopo aver completato la procedura guidata Configura origine dati, Visual Studio aggiungerà un oggetto BoundField per CategoryID, CategoryNameDescription, NumberOfProducts, e BrochurePath. Modificare GridView in modo che contenga solo e CategoryNameDescription BoundFields e aggiornare la CategoryName proprietà BoundField in HeaderText Category .
Aggiungere quindi un oggetto HyperLinkField e posizionarlo in modo che sia il campo più a sinistra. Impostare la DataNavigateUrlFields proprietà su CategoryID e la DataNavigateUrlFormatString proprietà su ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}. Impostare la Text proprietà su Visualizza prodotti .
Figura 6: Aggiungere un oggetto HyperLinkField a Categories GridView
Dopo aver creato ObjectDataSource e aver personalizzato i campi di GridView, il markup dichiarativo dei due controlli sarà simile al seguente:
<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>
La figura 7 mostra Default.aspx quando viene visualizzata tramite un browser. Facendo clic sul collegamento Visualizza prodotti di una categoria si passa a ProductsByCategory.aspx?CategoryID=categoryID, che verrà compilato nel passaggio 3.
Figura 7: Ogni categoria è elencata insieme a un collegamento Visualizza prodotti (fare clic per visualizzare l'immagine a dimensione intera)
Passaggio 3: Presentazione dei prodotti della categoria selezionata
Aprire la ProductsByCategory.aspx pagina e aggiungere un controllo GridView, assegnandogli un ProductsByCategorynome . Dallo smart tag associare GridView a un nuovo ObjectDataSource denominato ProductsByCategoryDataSource. Configurare ObjectDataSource per usare il ProductsBLL metodo della GetProductsByCategoryID(categoryID) classe e impostare gli elenchi a discesa su (Nessuno) nelle schede UPDATE, INSERT e DELETE.
Figura 8: Usare il ProductsBLL metodo della GetProductsByCategoryID(categoryID) classe (fare clic per visualizzare l'immagine a dimensione intera)
Il passaggio finale della procedura guidata Configura origine dati richiede un'origine parametro per categoryID. Poiché queste informazioni vengono passate tramite il campo CategoryIDquerystring , selezionare QueryString dall'elenco a discesa e immettere CategoryID nella casella di testo QueryStringField, come illustrato nella figura 9. Fare clic su Fine per completare la procedura guidata.
Figura 9: Usare il CategoryID campo Querystring per il parametro categoryID (fare clic per visualizzare l'immagine a dimensione intera)
Dopo aver completato la procedura guidata, Visual Studio aggiungerà i campi BoundField e checkBox corrispondenti a GridView per i campi dati del prodotto. Rimuovere tutti gli elementi , ProductNameUnitPricee SupplierName BoundFields. Personalizzare queste tre proprietà BoundFields HeaderText per leggere rispettivamente Product, Price e Supplier. Formattare BoundField UnitPrice come valuta.
Aggiungere quindi un oggetto HyperLinkField e spostarlo nella posizione più a sinistra. Impostarne la Text proprietà su Visualizza dettagli, la relativa DataNavigateUrlFields proprietà su ProductIDe la relativa DataNavigateUrlFormatString proprietà su ~/SiteMapProvider/ProductDetails.aspx?ProductID={0}.
Figura 10: Aggiungere un oggetto HyperLinkField dettagli visualizzazione a cui punta ProductDetails.aspx
Dopo aver apportato queste personalizzazioni, il markup dichiarativo di GridView e ObjectDataSource dovrebbe essere simile al seguente:
<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>
Tornare alla visualizzazione Default.aspx tramite un browser e fare clic sul collegamento Visualizza prodotti per bevande. Verranno visualizzati ProductsByCategory.aspx?CategoryID=1i nomi, i prezzi e i fornitori dei prodotti nel database Northwind che appartengono alla categoria Bevande (vedere la figura 11). È possibile migliorare ulteriormente questa pagina per includere un collegamento per restituire agli utenti la pagina dell'elenco di categorie (Default.aspx) e un controllo DetailsView o FormView che visualizza il nome e la descrizione della categoria selezionata.
Figura 11: Vengono visualizzati i nomi delle bevande, i prezzi e i fornitori (fare clic per visualizzare l'immagine a dimensione intera)
Passaggio 4: Visualizzazione dei dettagli di un prodotto
Nella pagina finale, ProductDetails.aspx, vengono visualizzati i dettagli dei prodotti selezionati. Aprire ProductDetails.aspx e trascinare un controllo DetailsView dalla casella degli strumenti nella finestra di progettazione. Impostare la proprietà DetailsView su ID e cancellare i ProductInfo valori delle proprietà e Height .Width Dallo smart tag associare DetailsView a un nuovo ObjectDataSource denominato ProductDataSource, configurando ObjectDataSource per eseguire il pull dei dati dal ProductsBLL metodo della classe .GetProductByProductID(productID) Come per le pagine Web precedenti create nei passaggi 2 e 3, impostare gli elenchi a discesa nelle schede UPDATE, INSERT e DELETE su (Nessuno).
Figura 12: Configurare ObjectDataSource per l'uso del metodo (fare clic per visualizzare l'immagine GetProductByProductID(productID)a dimensione intera)
L'ultimo passaggio della procedura guidata Configura origine dati richiede l'origine del parametro productID . Poiché questi dati provengono dal campo ProductIDquerystring , impostare l'elenco a discesa su QueryString e la casella di testo QueryStringField su ProductID. Infine, fare clic sul pulsante Fine per completare la procedura guidata.
Figura 13: Configurare il parametro productID per eseguire il pull del valore dal campo Querystring (fare clic per visualizzare l'immagine ProductIDa dimensione intera)
Dopo aver completato la procedura guidata Configura origine dati, Visual Studio creerà i campi BoundField corrispondenti e un controllo CheckBoxField nei campi DetailsView per i campi dati del prodotto.
ProductIDRimuovere i campi , SupplierIDe CategoryID BoundFields e configurare i campi rimanenti in base alle esigenze. Dopo alcune configurazioni estetiche, il markup dichiarativo di DetailsView e ObjectDataSource ha un aspetto simile al seguente:
<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>
Per testare questa pagina, tornare a Default.aspx e fare clic su Visualizza prodotti per la categoria Bevande. Nell'elenco dei prodotti per bevande fare clic sul collegamento Visualizza dettagli per Chai Tea.
ProductDetails.aspx?ProductID=1Verrà visualizzata la sezione , che mostra i dettagli di un tè Chai (vedere la figura 14).
Figura 14: Viene visualizzato Chai Tea s Supplier, Category, Price e Other Information (Fare clic per visualizzare l'immagine a dimensione intera)
Passaggio 5: Informazioni sui meccanismi interni di un provider di mappe del sito
La mappa del sito è rappresentata nella memoria del server Web come raccolta di SiteMapNode istanze che formano una gerarchia. Deve essere presente esattamente una radice, tutti i nodi non radice devono avere esattamente un nodo padre e tutti i nodi possono avere un numero arbitrario di elementi figlio. Ogni oggetto rappresenta una sezione della struttura del sito Web. Queste SiteMapNode sezioni in genere hanno una pagina Web corrispondente. Di conseguenza, la SiteMapNode classe ha proprietà come Title, Urle Description, che forniscono informazioni per la sezione rappresentata SiteMapNode da . Esiste anche una Key proprietà che identifica in modo univoco ogni SiteMapNode elemento nella gerarchia, nonché le proprietà usate per stabilire questa gerarchiaChildNodes, , ParentNodeNextSibling, PreviousSiblinge così via.
La figura 15 mostra la struttura generale della mappa del sito della figura 1, ma con i dettagli di implementazione delineati in dettaglio più fine.
Figura 15: Ognuna SiteMapNode ha proprietà come Title, Url, Keye così via (fare clic per visualizzare l'immagine a dimensione intera)
La mappa del sito è accessibile tramite la SiteMap Questa proprietà della RootNode classe restituisce l'istanza radice SiteMapNode della mappa del sito. CurrentNode Restituisce la SiteMapNode cui Url proprietà corrisponde all'URL della pagina attualmente richiesta. Questa classe viene usata internamente da ASP.NET controlli Web di spostamento 2.0.
Quando si accede alle proprietà della SiteMap classe, è necessario serializzare la struttura della mappa del sito da un supporto persistente in memoria. Tuttavia, la logica di serializzazione della mappa del sito non è hardcoded nella SiteMap classe . Al contrario, in fase di esecuzione la SiteMap classe determina il provider di mapping del sito da usare per la serializzazione. Per impostazione predefinita, viene utilizzata la XmlSiteMapProvider classe , che legge la struttura della mappa del sito da un file XML formattato correttamente. Tuttavia, con un po ' di lavoro possiamo creare il nostro provider di mappe del sito personalizzato.
Tutti i provider della SiteMapProvider mappa del sito devono essere derivati dalla classe , che include i metodi e le proprietà essenziali necessari per i provider di mappe del sito, ma omette molti dei dettagli di implementazione. Una seconda classe, StaticSiteMapProvider, estende la SiteMapProvider classe e contiene un'implementazione più affidabile delle funzionalità necessarie. Internamente, archivia le istanze della mappa del sito in un StaticSiteMapProvider e fornisce metodi come SiteMapNodee HashtableAddNode(child, parent) che aggiungono e rimuovono RemoveNode(siteMapNode), s all'interno Clear().SiteMapNodeHashtable L'oggetto XmlSiteMapProvider è derivato da StaticSiteMapProvider.
Quando si crea un provider di mappe del sito personalizzato che estende StaticSiteMapProvider, è necessario eseguire l'override di due metodi astratti: BuildSiteMap e GetRootNodeCore.
BuildSiteMap, come suggerisce il nome, è responsabile del caricamento della struttura della mappa del sito dall'archiviazione permanente e della sua costruzione in memoria.
GetRootNodeCore restituisce il nodo radice nella mappa del sito.
Prima che un'applicazione Web possa usare un provider della mappa del sito, deve essere registrata nella configurazione dell'applicazione. Per impostazione predefinita, la XmlSiteMapProvider classe viene registrata usando il nome AspNetXmlSiteMapProvider. Per registrare altri provider della mappa del sito, aggiungere il markup seguente a Web.config:
<configuration>
<system.web>
...
<siteMap defaultProvider="defaultProviderName">
<providers>
<add name="name" type="type" />
</providers>
</siteMap>
</system.web>
</configuration>
Il valore del nome assegna un nome leggibile al provider mentre il tipo specifica il nome completo del provider della mappa del sito. Verranno esaminati i valori concreti per il nome e i valori di tipo nel passaggio 7, dopo aver creato il provider di mappe del sito personalizzato.
Viene creata un'istanza della classe del provider della SiteMap mappa del sito la prima volta che si accede dalla classe e rimane in memoria per la durata dell'applicazione Web. Poiché esiste solo un'istanza del provider di mappe del sito che può essere richiamata da più visitatori del sito Web simultanei, è fondamentale che i metodi del provider siano thread-safe.
Per motivi di prestazioni e scalabilità, è importante memorizzare nella cache la struttura della mappa del sito in memoria e restituire questa struttura memorizzata nella cache anziché ricrearla ogni volta che viene richiamato il BuildSiteMap metodo.
BuildSiteMap può essere chiamato più volte per ogni richiesta di pagina per utente, a seconda dei controlli di spostamento in uso nella pagina e della profondità della struttura della mappa del sito. In ogni caso, se la struttura della mappa del sito non viene memorizzata nella cache in BuildSiteMap , ogni volta che viene richiamata, sarebbe necessario recuperare nuovamente le informazioni sul prodotto e la categoria dall'architettura ( il che comporterebbe una query nel database). Come illustrato nelle esercitazioni precedenti sulla memorizzazione nella cache, i dati memorizzati nella cache possono diventare obsoleti. Per risolvere questo problema, è possibile usare le scadenze basate sulle dipendenze della cache SQL o time-based.
Nota
Un provider della mappa del sito può facoltativamente eseguire l'override del Initialize metodo .
Initializeviene richiamato quando viene creata la prima istanza del provider della mappa del sito e viene passato qualsiasi attributo personalizzato assegnato al provider nell'elemento Web.config<add> , ad esempio . <add name="name" type="type" customAttribute="value" /> È utile se si vuole consentire a uno sviluppatore di pagine di specificare varie impostazioni correlate al provider della mappa del sito senza dover modificare il codice del provider. Ad esempio, se si leggevano i dati di categoria e prodotti direttamente dal database anziché tramite l'architettura, è probabile che lo sviluppatore della pagina specifichi il database stringa di connessione tramite Web.config anziché usare un valore hardcoded nel codice del provider. Il provider della mappa del sito personalizzato che verrà compilato nel passaggio 6 non esegue l'override di questo Initialize metodo. Per un esempio dell'uso del Initialize metodo , vedere l'articolo Archiviazione di mappe del sito in SQL Server di Jeff Prosise.
Passaggio 6: Creazione del provider della mappa del sito personalizzato
Per creare un provider di mappe del sito personalizzato che compila la mappa del sito dalle categorie e dai prodotti nel database Northwind, è necessario creare una classe che estende StaticSiteMapProvider. Nel passaggio 1 ti ho chiesto di aggiungere una CustomProviders cartella nella App_Code cartella - aggiungere una nuova classe a questa cartella denominata NorthwindSiteMapProvider. Aggiungere il codice seguente alla classe NorthwindSiteMapProvider:
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
Iniziamo con l'esplorazione di questo metodo della BuildSiteMap classe, che inizia con un'istruzionelock. L'istruzione lock consente l'immissione di un solo thread alla volta, serializzando così l'accesso al codice e impedendo a due thread simultanei di eseguire l'istruzione uno sull'altro.
La variabile a livello SiteMapNode di classe viene usata per memorizzare root nella cache la struttura della mappa del sito. Quando la mappa del sito viene costruita per la prima volta o per la prima volta dopo la modifica dei dati sottostanti, root sarà Nothing e verrà costruita la struttura della mappa del sito. Il nodo radice della mappa del sito viene assegnato durante root il processo di costruzione in modo che la volta successiva che questo metodo venga chiamato, root non sarà Nothing. Di conseguenza, purché root non Nothing sia la struttura della mappa del sito verrà restituita al chiamante senza dover ricrearla.
Se root è Nothing, la struttura della mappa del sito viene creata dalle informazioni sul prodotto e sulla categoria. La mappa del sito viene compilata creando le SiteMapNode istanze e quindi formando la gerarchia tramite chiamate al StaticSiteMapProvider metodo della AddNode classe .
AddNode esegue la contabilità interna, archiviando SiteMapNode le istanze assortite in un oggetto Hashtable. Prima di iniziare a costruire la gerarchia, si inizia chiamando il Clear metodo , che cancella gli elementi dall'oggetto interno Hashtable. Successivamente, il ProductsBLL metodo s GetProducts della classe e il risultato ProductsDataTable vengono archiviati nelle variabili locali.
La costruzione della mappa del sito inizia creando il nodo radice e assegnandolo a root. L'overload SiteMapNode del costruttore usato qui e in tutto questo BuildSiteMap viene passato quanto segue:
- Riferimento al provider della mappa del sito (
Me). - Oggetto
SiteMapNodesKey. Questo valore obbligatorio deve essere univoco per ogniSiteMapNodeoggetto . - Oggetto
SiteMapNodesUrl.Urlè facoltativo, ma se specificato, ogniSiteMapNodevalore deveUrlessere univoco. - L'oggetto
SiteMapNodesTitle, obbligatorio.
La AddNode(root) chiamata al metodo aggiunge l'oggetto SiteMapNoderoot alla mappa del sito come radice. Successivamente, ognuno ProductRow di essi ProductsDataTable viene enumerato. Se esiste già un oggetto SiteMapNode per la categoria del prodotto corrente, viene fatto riferimento. In caso contrario, viene creato un nuovo SiteMapNode oggetto per la categoria e aggiunto come elemento figlio di SiteMapNode``root tramite la chiamata al AddNode(categoryNode, root) metodo. Dopo aver trovato o creato il nodo di categoria SiteMapNode appropriato, viene creato un SiteMapNode oggetto per il prodotto corrente e aggiunto come elemento figlio della categoria SiteMapNode tramite AddNode(productNode, categoryNode). Si noti che il valore della proprietà della categoria SiteMapNode è Url mentre alla proprietà del ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID prodotto SiteMapNode viene assegnato Url.~/SiteMapNode/ProductDetails.aspx?ProductID=productID
Nota
I prodotti con un valore di database per il relativo NULL vengono CategoryID raggruppati in una categoria SiteMapNode la cui Title proprietà è impostata su Nessuno e la cui Url proprietà è impostata su una stringa vuota. Ho deciso di impostare Url su una stringa vuota perché il ProductBLL metodo della GetProductsByCategory(categoryID) classe attualmente non ha la possibilità di restituire solo quei prodotti con un NULLCategoryID valore. Inoltre, volevo dimostrare come i controlli di spostamento eseguono il rendering di un oggetto SiteMapNode che non ha un valore per la relativa Url proprietà. Ti invito a estendere questa esercitazione SiteMapNode in modo che la proprietà Nessuno punti Url a ProductsByCategory.aspx, ma visualizza solo i prodotti con NULLCategoryID valori.
Dopo aver costruito la mappa del sito, un oggetto arbitrario viene aggiunto alla cache dei dati usando una dipendenza della cache SQL dalle Categories tabelle e Products tramite un AggregateCacheDependency oggetto . È stato esaminato l'uso delle dipendenze della cache SQL nell'esercitazione precedente, Uso delle dipendenze della cache SQL. Il provider della mappa del sito personalizzato, tuttavia, usa un overload del metodo della Insert cache dei dati ancora da esplorare. Questo overload accetta come parametro di input finale un delegato chiamato quando l'oggetto viene rimosso dalla cache. In particolare, viene passato un nuovo CacheItemRemovedCallback delegato che punta al OnSiteMapChanged metodo definito più avanti nella NorthwindSiteMapProvider classe .
Nota
La rappresentazione in memoria della mappa del sito viene memorizzata nella cache tramite la variabile roota livello di classe . Poiché è presente una sola istanza della classe provider del provider della mappa del sito personalizzata e poiché tale istanza viene condivisa tra tutti i thread nell'applicazione Web, questa variabile di classe funge da cache. Il BuildSiteMap metodo usa anche la cache dei dati, ma solo come mezzo per ricevere una notifica quando cambiano i dati del database sottostanti nelle Categories tabelle o Products . Si noti che il valore inserito nella cache dei dati è solo la data e l'ora correnti. I dati effettivi della mappa del sito non sono inseriti nella cache dei dati.
Il BuildSiteMap metodo viene completato restituendo il nodo radice della mappa del sito.
I metodi rimanenti sono piuttosto semplici.
GetRootNodeCore è responsabile della restituzione del nodo radice. Poiché BuildSiteMap restituisce la radice, GetRootNodeCore restituisce BuildSiteMap semplicemente il valore restituito. Il OnSiteMapChanged metodo torna root a Nothing quando l'elemento della cache viene rimosso. Con root impostato di nuovo su Nothing, la volta BuildSiteMap successiva viene richiamata, la struttura della mappa del sito verrà ricompilata. Infine, la CachedDate proprietà restituisce il valore di data e ora archiviato nella cache dei dati, se tale valore esiste. Questa proprietà può essere utilizzata da uno sviluppatore di pagine per determinare quando i dati della mappa del sito sono stati memorizzati nella cache.
Passaggio 7: Registrazione diNorthwindSiteMapProvider
Per consentire all'applicazione Web di usare il provider della mappa del NorthwindSiteMapProvider sito creato nel passaggio 6, è necessario registrarlo nella <siteMap> sezione di Web.config. In particolare, aggiungere il markup seguente all'interno dell'elemento <system.web> in Web.config:
<siteMap defaultProvider="AspNetXmlSiteMapProvider">
<providers>
<add name="Northwind" type="NorthwindSiteMapProvider" />
</providers>
</siteMap>
Questo markup esegue due operazioni: per prima cosa, indica che il AspNetXmlSiteMapProvider provider predefinito della mappa del sito è il provider di mappe del sito predefinito. In secondo luogo, registra il provider della mappa del sito personalizzato creato nel passaggio 6 con il nome descrittivo Northwind.
Nota
Per i provider della mappa del sito che si trovano nella cartella dell'applicazione App_Code , il valore dell'attributo type è semplicemente il nome della classe. In alternativa, il provider personalizzato della mappa del sito potrebbe essere stato creato in un progetto di libreria di classi separato con l'assembly compilato inserito nella directory dell'applicazione /Bin Web. In tal caso, il valore dell'attributo type sarà Namespace.ClassName, AssemblyName.
Dopo l'aggiornamento Web.config, dedicare qualche minuto alla visualizzazione di qualsiasi pagina delle esercitazioni in un browser. Si noti che l'interfaccia di spostamento a sinistra mostra ancora le sezioni e le esercitazioni definite in Web.sitemap. Ciò è dovuto al fatto che è stato lasciato AspNetXmlSiteMapProvider come provider predefinito. Per creare un elemento dell'interfaccia utente di navigazione che usa NorthwindSiteMapProvider, è necessario specificare in modo esplicito che deve essere usato il provider di mappe del sito Northwind. Si vedrà come eseguire questa operazione nel passaggio 8.
Passaggio 8: Visualizzazione delle informazioni sulla mappa del sito tramite il provider di mappe siti personalizzato
Con il provider di mappe del sito personalizzato creato e registrato in Web.config, è possibile aggiungere controlli di spostamento alle Default.aspxpagine , ProductsByCategory.aspxe ProductDetails.aspx nella SiteMapProvider cartella . Per iniziare, aprire la Default.aspx pagina e trascinare un SiteMapPath oggetto dalla casella degli strumenti nella finestra di progettazione. Il controllo SiteMapPath si trova nella sezione Navigazione della casella degli strumenti.
Figura 16: Aggiungere un Oggetto SiteMapPath a Default.aspx (fare clic per visualizzare un'immagine a dimensione intera)
Il controllo SiteMapPath visualizza un percorso di navigazione che indica la posizione della pagina corrente all'interno della mappa del sito. È stato aggiunto un Oggetto SiteMapPath all'inizio della pagina master nell'esercitazione Pagine master e navigazione sito .
Dedicare un attimo alla visualizzazione di questa pagina tramite un browser. SiteMapPath aggiunto nella figura 16 usa il provider predefinito della mappa del sito, estraendone i dati da Web.sitemap. Di conseguenza, la barra di navigazione mostra Home > Personalizzazione della mappa del sito, proprio come la barra di navigazione nell'angolo superiore destro.
Figura 17: Il percorso di navigazione usa il provider predefinito della mappa del sito (fare clic per visualizzare l'immagine a dimensione intera)
Per aggiungere SiteMapPath nella figura 16, usare il provider della mappa del sito personalizzato creato nel passaggio 6, impostarne la SiteMapProvider proprietà su Northwind, il nome assegnato a NorthwindSiteMapProvider in Web.config. Sfortunatamente, la finestra di progettazione continua a usare il provider predefinito della mappa del sito, ma se si visita la pagina tramite un browser dopo aver apportato questa modifica alla proprietà, si noterà che il percorso di navigazione usa ora il provider della mappa del sito personalizzato.
Figura 18: Il percorso di navigazione usa ora il provider NorthwindSiteMapProvider di mappe siti personalizzato (fare clic per visualizzare l'immagine a dimensione intera)
Il controllo SiteMapPath visualizza un'interfaccia utente più funzionale nelle ProductsByCategory.aspx pagine e ProductDetails.aspx . Aggiungere un Oggetto SiteMapPath a queste pagine, impostando la SiteMapProvider proprietà in entrambi su Northwind. Fare Default.aspx clic sul collegamento Visualizza prodotti per bevande e quindi sul collegamento Visualizza dettagli per Chai Tea. Come illustrato nella figura 19, la barra di navigazione include la sezione corrente della mappa del sito ( Chai Tea ) e i relativi predecessori: Bevande e Tutte le categorie .
Figura 19: Il percorso di navigazione usa ora il provider NorthwindSiteMapProvider di mappe siti personalizzato (fare clic per visualizzare l'immagine a dimensione intera)
È possibile usare altri elementi dell'interfaccia utente di navigazione oltre a SiteMapPath, ad esempio i controlli Menu e TreeView. Le Default.aspxpagine , ProductsByCategory.aspxe ProductDetails.aspx nel download per questa esercitazione, ad esempio, includono tutti i controlli Menu (vedere la figura 20). Per informazioni più approfondite sui controlli di spostamento e sul sistema mappa del sito in ASP.NET 2.0, vedere ASP.NET 2.0 Sofisticate funzionalità di spostamento del sito e la sezione Uso dei controlli di spostamento e dei controlli della mappa del sito di ASP.NET 2.0.
Figura 20: Il controllo menu elenca ognuna delle categorie e dei prodotti (fare clic per visualizzare l'immagine a dimensione intera)
Come accennato in precedenza in questa esercitazione, è possibile accedere alla struttura della mappa del sito a livello di codice tramite la SiteMap classe . Il codice seguente restituisce la radice SiteMapNode del provider predefinito:
Dim root As SiteMapNode = SiteMap.RootNode
AspNetXmlSiteMapProvider Poiché è il provider predefinito per l'applicazione, il codice precedente restituirà il nodo radice definito in Web.sitemap. Per fare riferimento a un provider della mappa del sito diverso da quello predefinito, usare la SiteMap proprietàProviders classe come segue:
Dim root As SiteMapNode = SiteMap.Providers("name").RootNode
Dove name è il nome del provider personalizzato della mappa del sito ( Northwind, per l'applicazione Web).
Per accedere a un membro specifico di un provider della mappa del sito, usare SiteMap.Providers["name"] per recuperare l'istanza del provider e quindi eseguirne il cast al tipo appropriato. Ad esempio, per visualizzare la NorthwindSiteMapProvider proprietà s CachedDate in una pagina ASP.NET, usare il codice seguente:
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
Nota
Assicurarsi di testare la funzionalità di dipendenza della cache SQL. Dopo aver visitato le Default.aspxpagine , ProductsByCategory.aspxe ProductDetails.aspx , passare a una delle esercitazioni nella sezione Modifica, inserimento ed eliminazione e modificare il nome di una categoria o di un prodotto. Tornare quindi a una delle pagine nella SiteMapProvider cartella . Supponendo che sia trascorso un tempo sufficiente per il meccanismo di polling per prendere nota della modifica al database sottostante, la mappa del sito deve essere aggiornata per visualizzare il nuovo nome di prodotto o categoria.
Riepilogo
ASP.NET funzionalità della mappa del sito di 2.0 include una classe, un SiteMap numero di controlli Web di spostamento predefiniti e un provider di mappe del sito predefinito che prevede la persistenza delle informazioni sulla mappa del sito in un file XML. Per usare le informazioni sulla mappa del sito da un'altra origine, ad esempio da un database, dall'architettura dell'applicazione o da un servizio Web remoto, è necessario creare un provider di mappe del sito personalizzato. Ciò comporta la creazione di una classe che deriva, direttamente o indirettamente, dalla SiteMapProvider classe .
In questa esercitazione è stato illustrato come creare un provider di mappe del sito personalizzato basato sulla mappa del sito sulle informazioni sul prodotto e sulle categorie generate dall'architettura dell'applicazione. Il provider ha esteso la StaticSiteMapProvider classe e comportato la creazione di un BuildSiteMap metodo che ha recuperato i dati, costruito la gerarchia della mappa del sito e memorizzato nella cache la struttura risultante in una variabile a livello di classe. È stata usata una dipendenza della cache SQL con una funzione di callback per invalidare la struttura memorizzata nella cache quando vengono modificati i dati o Categories sottostantiProducts.
Buon programmatori!
Altre informazioni
Per altre informazioni sugli argomenti illustrati in questa esercitazione, vedere le risorse seguenti:
- Archiviazione di mappe del sito in SQL Server e provider della mappa del sito SQL in attesa
- Il Toolkit del Fornitore
- ASP.NET 2.0 funzionalità sofisticate di spostamento sito
Informazioni sull'autore
Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Può essere raggiunto a mitchell@4GuysFromRolla.com.
Grazie speciale a
Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori principali per questa esercitazione erano Dave Gardner, Zack Jones, Teresa Murphy e Bernadette Leigh. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, mandami un messaggio a mitchell@4GuysFromRolla.com.