Condividi tramite


Creazione di un provider personalizzato di mappe di siti basate su database (VB)

di Scott Mitchell

Scarica PDF

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 creeremo un provider di mappe del sito personalizzato che recupera i dati dallo strato di logica aziendale, che a sua volta li ottiene 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. Nell'esercitazione Pagine master e navigazione del sito, avevamo creato un file denominato Web.sitemap che conteneva questa struttura e il cui XML è stato aggiornato 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.

Le categorie e i prodotti costituiscono la struttura della mappa del sito

Figura 1: Le categorie e i prodotti compongono la 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é la serializzazione della mappa del sito di ASP.NET 2.0 è basata sul modello di provider, è possibile creare il proprio provider di mappa del sito personalizzato che recupera i dati da un archivio dati alternativo, come un database o un'altra 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, negli articoli Archiviare le mappe del sito in SQL Server e Il provider di mappe del sito SQL che stavate aspettando, esamina un approccio generalizzato all'archiviazione dei dati delle mappe 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.aspx
  • ProductsByCategory.aspx
  • ProductDetails.aspx

Aggiungere anche una CustomProviders sottocartella alla App_Code cartella .

Aggiungere le pagine ASP.NET per i tutorial correlati al provider della mappa del sito

Figura 2: Aggiungi le pagine ASP.NET per i tutorial relativi al provider della mappa del sito

Poiché è disponibile una sola esercitazione per questa sezione, non è necessario Default.aspx elencare le esercitazioni della sezione. Invece, le categorie verranno visualizzate in un controllo GridView Default.aspx. Questo argomento verrà affrontato nel passaggio 2.

Quindi, aggiornare Web.sitemap per includere un riferimento alla Default.aspx. 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, prendersi qualche minuto per visualizzare il sito dei tutorial tramite un browser. Il menu a sinistra include ora una voce per il solo tutorial del fornitore della mappa del sito.

La mappa del sito ora include una voce per il tutorial del provider della mappa del sito

Figura 3: La mappa del sito include ora una voce per il tutorial sul fornitore della mappa 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é l'obiettivo principale di questa esercitazione è sui provider di mappe del sito, e dato che le esercitazioni precedenti hanno trattato la creazione di questo tipo di report master/dettagli multi-pagina, accelereremo attraverso i passaggi da 2 a 4. Se hai bisogno di un ripasso sulla creazione di report master/dettaglio che si estendono su più pagine, fai riferimento all'esercitazione Filtraggio master/dettaglio su due pagine.

Passaggio 2: Visualizzazione di un elenco di categorie

Aprire la pagina Default.aspx nella cartella SiteMapProvider e trascinare GridView dalla Toolbox nella finestra di progettazione, impostandone le proprietà su ID a Categories. Associando il GridView al suo Smart Tag, associarlo a un nuovo ObjectDataSource denominato CategoriesDataSource e configurarlo in modo che recuperi i dati usando il metodo GetCategories della classe CategoriesBLL. 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).

Configurare ObjectDataSource per restituire categorie usando il metodo GetCategories

Figura 4: Configurare ObjectDataSource per restituire categorie usando il metodo GetCategories (clicca per visualizzare l'immagine a schermo intero)

Impostare gli elenchi a discesa nelle schede UPDATE, INSERT e DELETE su (Nessuno)

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 i CategoryName e Description BoundFields e aggiornare il BoundField CategoryName alla proprietà 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 .

Aggiungere un oggetto HyperLinkField alle categorie GridView

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.

Ogni categoria è elencata insieme a un collegamento Visualizza prodotti

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 pagina ProductsByCategory.aspx e aggiungere un controllo GridView, assegnandole il nome ProductsByCategory. Con lo smart tag, collega il 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.

Utilizzare il metodo GetProductsByCategoryID(categoryID) della classe ProductsBLL

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.

Usare il campo Querystring CategoryID per il parametro categoryID

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 eccetto ProductName, UnitPrice e SupplierName BoundFields. Personalizzare queste tre proprietà di BoundFields HeaderText per leggere rispettivamente Prodotto, Prezzo e Fornitore. Formatta il UnitPrice BoundField 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}.

Aggiungi un HyperLinkField per visualizzare i dettagli che punta a ProductDetails.aspx

Figura 10: Aggiungere un HyperLinkField Visualizza Dettagli che punta a 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. Verrai indirizzato a ProductsByCategory.aspx?CategoryID=1, dove verranno visualizzati i 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.

Vengono visualizzati i nomi delle bevande, i prezzi e i fornitori

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à ID di DetailsView su ProductInfo e cancellare i valori delle sue proprietà Height e Width. Dallo smart tag, vincolare DetailsView a un nuovo ObjectDataSource denominato ProductDataSource, configurando ObjectDataSource per recuperare i dati dal metodo GetProductByProductID(productID) della classe ProductsBLL. 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).

Configurare ObjectDataSource per l'utilizzo del metodo GetProductByProductID(productID)

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.

Configurare il parametro productID per eseguire il pull del relativo valore dal campo Querystring ProductID

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 corrispondenti BoundFields e un CheckBoxField nel DetailsView per i dati del prodotto. Rimuovere i BoundFields ProductID, SupplierID e CategoryID, 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. Questo ti porterà a ProductDetails.aspx?ProductID=1, che mostra i dettagli di un tè Chai (vedere la figura 14).

Sono visualizzati i dati del fornitore di Chai Tea, la categoria, il prezzo e altre informazioni

Figura 14: Vengono visualizzati il Fornitore di Chai Tea, la Categoria, il Prezzo e le Altre Informazioni (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.

Ogni SiteMapNode ha proprietà come titolo, URL, chiave e così via

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 classe SiteMap nel namespace System.Web. Questa proprietà della RootNode classe restituisce l'istanza radice SiteMapNode della site map. CurrentNode restituisce la SiteMapNode cui Url proprietà corrisponde all'URL della pagina attualmente richiesta. Questa classe viene utilizzata internamente dai controlli Web di navigazione di ASP.NET 2.0.

Quando si accede alle proprietà della classe SiteMap, è necessario serializzare la struttura della mappa del sito da un supporto persistente in memoria. Tuttavia, la logica di serializzazione della mappa del sito non è codificata in modo fisso nella classe SiteMap. 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 di mappe del sito devono derivare dalla classe SiteMapProvider, 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, il StaticSiteMapProvider archivia le istanze della mappa del sito in un SiteMapNode e fornisce metodi come AddNode(child, parent), RemoveNode(siteMapNode), e Clear() che aggiungono e rimuovono SiteMapNode all'interno del Hashtable. 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 di sitemap, 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 il tipo nel Passaggio 7, dopo aver creato il nostro provider personalizzato della mappa del sito.

Viene istanziata la classe del provider della mappa del sito la prima volta che vi si accede dalla classe SiteMap stessa e rimane in memoria per tutta 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 affrontare questo, è possibile utilizzare scadenze basate su dipendenze della cache SQL o su tempo.

Nota

Facoltativamente, un fornitore della mappa del sito può eseguire l'override del Initialize metodo. Initialize viene richiamato quando il provider della mappa del sito viene istanziato per la prima volta e vengono passati eventuali attributi personalizzati assegnati al provider in Web.config nell'elemento <add>, come 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 leggessimo i dati delle categorie e dei prodotti direttamente dal database anziché attraverso l'architettura, probabilmente vorremmo che lo sviluppatore della pagina specifichi la stringa di connessione al database tramite Web.config anziché utilizzare un valore codificato nel codice del provider. Il provider della mappa del sito personalizzato che verrà costruito nel passaggio 6 non sovrascrive 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 lock'istruzione. L'istruzione lock consente l'accesso di un solo thread alla volta, serializzando così l'accesso al codice e impedendo a due thread concorrenti di interferire l'uno con l'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 a root durante 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 formando la gerarchia tramite chiamate al metodo della classe StaticSiteMapProviderAddNode. 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. Il sovraccarico del SiteMapNode costruttore utilizzato qui e in tutto questo BuildSiteMap riceve le seguenti informazioni:

  • Riferimento al provider della mappa del sito (Me).
  • Il SiteMapNode s Key. Questo valore obbligatorio deve essere univoco per ogni oggetto SiteMapNode.
  • Il SiteMapNode s Url. Url è facoltativo, ma se specificato, ogni SiteMapNode valore deve Url essere univoco.
  • Il componente SiteMapNode s Title è obbligatorio.

La chiamata al metodo AddNode(root) aggiunge SiteMapNoderoot come radice alla mappa del sito. Successivamente, ogni ProductRow nel 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 oggetto SiteMapNode per la categoria e aggiunto come elemento figlio di SiteMapNode``root tramite il metodo AddNode(categoryNode, root). 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 affinché la proprietà None punti su ProductsByCategory.aspx, ma mostri solo i prodotti con i valori NULLCategoryID.

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 personalizzato della mappa del sito, tuttavia, utilizza un overload del metodo della Insert cache dei dati che dobbiamo ancora 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 il root reimpostato su Nothing, la prossima volta che si richiama BuildSiteMap, 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 alla nostra applicazione web di usare il provider della mappa del sito NorthwindSiteMapProvider creato nel Passo 6, è necessario registrarlo nella sezione <siteMap> 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 incorporato è il provider predefinito della mappa del sito. In secondo luogo, registra il provider personalizzato della mappa del sito creato nel passaggio 6 con il nome facile da comprendere 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 /Bin dell'applicazione web. In tal caso, il valore dell'attributo type sarà Namespace.ClassName, AssemblyName.

Dopo l'aggiornamento Web.config, dedica qualche minuto per visualizzare qualsiasi pagina dei tutorial 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 mappa del sito personalizzato creato e registrato in Web.config, siamo pronti ad aggiungere i controlli di navigazione alle pagine Default.aspx, ProductsByCategory.aspx e ProductDetails.aspx nella cartella SiteMapProvider. 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.

Aggiungere un Oggetto SiteMapPath a Default.aspx

Figura 16: Aggiungere un Oggetto SiteMapPath a Default.aspx (fare clic per visualizzare un'immagine a dimensione intera)

Il controllo SiteMapPath visualizza un breadcrumb che indica la posizione della pagina corrente all'interno della sitemap. Abbiamo aggiunto un SiteMapPath nella parte superiore 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.

Il breadcrumb utilizza il provider predefinito della mappa del sito

Figura 17: Il breadcrumb usa il provider predefinito della mappa del sito (fare clic per visualizzare a dimensione intera l'immagine)

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, il Designer 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 breadcrumb ora utilizza il provider della mappa del sito personalizzato.

Screenshot che mostra come il breadcrumb visualizza il provider della mappa del sito personalizzata.

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 maggiormente funzionale sulle pagine ProductsByCategory.aspx e ProductDetails.aspx. Aggiungere un SiteMapPath a queste pagine, impostando la SiteMapProvider proprietà in entrambe su Northwind. Fare clic su Default.aspx collegamento Visualizza prodotti per le 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 .

Screenshot che mostra come la barra di navigazione visualizza la sezione della mappa del sito corrente (Chai Tea) e i relativi predecessori (Bevande e Tutte le categorie).

Figura 19: Il percorso di navigazione ora utilizza il provider di sitemap personalizzato NorthwindSiteMapProvider (fare clic per visualizzare l'immagine a grandezza naturale)

È possibile usare altri elementi dell'interfaccia utente di navigazione oltre a SiteMapPath, ad esempio i controlli Menu e TreeView. Le pagine Default.aspx, ProductsByCategory.aspx e ProductDetails.aspx nel download per questa esercitazione, ad esempio, includono i controlli Menu (vedere la figura 20). Per un approfondimento sui controlli di navigazione e sul sistema di mappa del sito in ASP.NET 2.0, vedere le sofisticate funzionalità di navigazione del sito di ASP.NET 2.0 e la sezione Usare i controlli di navigazione nel ASP.NET 2.0 QuickStarts.

Il controllo Menu elenca ognuna delle categorie e dei prodotti

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, utilizzare la classe con la proprietà come segue:

Dim root As SiteMapNode = SiteMap.Providers("name").RootNode

Dove name indica il nome del fornitore di mappe del sito personalizzato (Northwind, per la nostra applicazione web).

Per accedere al membro specifico di un provider della mappa del sito, usare SiteMap.Providers["name"] per recuperare l'istanza del provider e quindi fare 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 pagine Default.aspx, ProductsByCategory.aspx e ProductDetails.aspx, accedere a uno dei tutorial 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

Le funzionalità della mappa del sito di ASP.NET 2.0 includono una classe, un numero di SiteMap controlli Web di navigazione integrati 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, abbiamo visto come creare un provider personalizzato per le mappe del sito basato sulle informazioni sui prodotti e sulle categorie derivate dall'architettura dell'applicazione. Il nostro provider ha esteso la StaticSiteMapProvider classe e ha comportato la creazione di un BuildSiteMap metodo che recuperava i dati, costruiva la gerarchia della mappa del sito e memorizzava la struttura risultante nella cache in una variabile di classe. È stata utilizzata una dipendenza di cache SQL con una funzione di callback per invalidare la struttura memorizzata nella cache quando i dati sottostanti Categories o Products vengono modificati.

Buon programmatori!

Altre informazioni

Per altre informazioni sugli argomenti illustrati in questa esercitazione, vedere le risorse seguenti:

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 diversi revisori validi. I revisori principali di questo tutorial 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.