Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Standardprovidern för webbplatsöversikt i ASP.NET 2.0 hämtar sina data från en statisk XML-fil. Den XML-baserade providern är lämplig för många små och medelstora webbplatser, men större webbprogram kräver en mer dynamisk webbplatskarta. I den här handledningen skapar vi en anpassad sajtöversiktsleverantör som hämtar sina data från affärslogiklagret, som i sin tur hämtar data från databasen.
Inledning
ASP.NET 2.0:s webbplatskartsfunktion gör det möjligt för en sidutvecklare att definiera en webbapplikations webbplatskarta i något beständigt medium, till exempel i en XML-fil. När de har definierats kan webbplatsöversiktsdata nås programmatiskt via SiteMap
klassen i System.Web
namnområdet eller via en mängd olika navigeringswebbkontroller, till exempel kontrollerna SiteMapPath, Menu och TreeView. Platskartsystemet använder providermodellen så att olika implementeringar av webbplatskartans serialisering kan skapas och anslutas till ett webbprogram. Standardprovidern för webbplatskartor som levereras med ASP.NET 2.0 bevarar webbplatskartans struktur i en XML-fil. I självstudien Huvudsidor och Webbplatsnavigering skapade vi en fil med namnet Web.sitemap
som innehöll den här strukturen och har uppdaterat dess XML med varje nytt självstudieavsnitt.
Standardprovidern för XML-baserad webbplatskarta fungerar bra om webbplatskartans struktur är ganska statisk, till exempel för de här självstudierna. I många scenarier behövs dock en mer dynamisk webbplatskarta. Överväg webbplatskartan som visas i bild 1, där varje kategori och produkt visas som avsnitt i webbplatsens struktur. Med den här webbplatskartan kan det hända att en lista över alla kategorier visas på den webbsida som motsvarar rotnoden, medan en viss kategoris webbsida visar den kategorins produkter och en viss produkts webbsida visar informationen om produkten.
Bild 1: Kategorierna och produkterna sminkar webbplatskartans struktur (Klicka om du vill visa en bild i full storlek)
Även om den här kategori- och produktbaserade strukturen kan hårdkodas i Web.sitemap
filen, måste filen uppdateras varje gång en kategori eller produkt har lagts till, tagits bort eller bytt namn. Därför skulle underhållet av webbplatskartan förenklas avsevärt om dess struktur hämtades från databasen eller helst från affärslogiklagret i programmets arkitektur. På så sätt, när produkter och kategorier har lagts till, bytt namn eller tagits bort, uppdateras webbplatskartan automatiskt för att återspegla dessa ändringar.
Eftersom ASP.NET 2,0-s webbplatskartans serialisering har skapats ovanpå providermodellen kan vi skapa en egen anpassad webbplatsöversiktsprovider som hämtar sina data från ett alternativt datalager, till exempel databasen eller arkitekturen. I den här handledningen kommer vi att skapa en anpassad tjänst som hämtar sina data från BLL:n. Låt oss komma igång!
Anmärkning
Den anpassade webbplatsöversiktsprovidern som skapades i den här självstudien är nära kopplad till programmets arkitektur och datamodell. Jeff Prosises artiklar Storing Site Maps in SQL Server och The SQL Site Map Provider You’ve Been Waiting For undersöker ett generellt tillvägagångssätt för att lagra webbplatskartsdata i SQL Server.
Steg 1: Skapa webbsidor för anpassad webbplatskartaleverantör
Innan vi börjar skapa en anpassad webbplatsöversiktsprovider ska vi först lägga till de ASP.NET sidor som vi behöver för den här självstudien. Börja med att lägga till en ny mapp med namnet SiteMapProvider
. Lägg sedan till följande ASP.NET sidor i mappen och se till att associera varje sida med Site.master
huvudsidan:
Default.aspx
ProductsByCategory.aspx
ProductDetails.aspx
Lägg också till en CustomProviders
undermapp i App_Code
mappen.
Bild 2: Lägg till ASP.NET sidor för webbplatsöversikten Provider-Related självstudier
Eftersom det bara finns en självstudiekurs för det här avsnittet, behöver vi inte Default.aspx
lista avsnittets självstudiekurser.
Default.aspx
I stället visas kategorierna i en GridView-kontroll. Vi tar itu med detta i steg 2.
Uppdatera Web.sitemap
sedan för att inkludera en referens till Default.aspx
sidan. Mer specifikt lägger du till följande markering efter cachelagringen <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." />
Efter att du har uppdaterat Web.sitemap
, ta en stund att besöka självstudiewebbplatsen via en webbläsare. Menyn till vänster innehåller nu ett objekt för handledningen för den enda leverantören av webbplatskartor.
Bild 3: Webbplatsöversikten innehåller nu en post för självstudiekursen för webbplatsöversiktsprovider
Den här självstudiekursen fokuserar främst på att illustrera hur du skapar en anpassad webbplatsöversiktsprovider och konfigurerar ett webbprogram för att använda den providern. I synnerhet skapar vi en provider som returnerar en webbplatskarta som innehåller en rotnod tillsammans med en nod för varje kategori och produkt, enligt bild 1. I allmänhet kan varje nod i webbplatsöversikten ange en URL. För vår webbplatskarta blir ~/SiteMapProvider/Default.aspx
rotnodens URL , som listar alla kategorier i databasen. Varje kategorinod i webbplatsöversikten har en URL som pekar på ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID
, som visar alla produkter i det angivna categoryID:et. Slutligen pekar varje nod på produktwebbplatskartan på ~/SiteMapProvider/ProductDetails.aspx?ProductID=productID
, som visar den specifika produktinformationen.
För att börja måste vi skapa Default.aspx
sidorna , ProductsByCategory.aspx
och ProductDetails.aspx
. Dessa sidor har slutförts i steg 2, 3 respektive 4. Eftersom syftet med den här självstudien är att fokusera på leverantörer av webbplatskartor, och eftersom tidigare självstudier har täckt hur man skapar den här typen av master/detalj-rapporter med flera sidor, kommer vi att snabbt gå igenom steg 2 till 4. Om du behöver en uppdatering för att skapa huvud-/detaljrapporter som sträcker sig över flera sidor kan du gå tillbaka till självstudien Master/Detail Filtering Across Two Pages (Huvud-/detaljfiltrering över två sidor ).
Steg 2: Visa en lista med kategorier
Öppna sidan Default.aspx
i SiteMapProvider
mappen och dra en GridView från verktygslådan till designern och ställ in den ID
på Categories
. Från GridViews smarta tagg binder du den till en ny ObjectDataSource med namnet CategoriesDataSource
och konfigurerar den så att den hämtar sina data med hjälp av CategoriesBLL
klassens GetCategories
-metod. Eftersom den här GridView bara visar kategorierna och inte tillhandahåller funktioner för datamodifiering anger du listrutorna på flikarna UPDATE, INSERT och DELETE till (Ingen) .
Bild 4: Konfigurera ObjectDataSource för att returnera kategorier med hjälp av GetCategories
metoden (Klicka om du vill visa en bild i full storlek)
Bild 5: Ange Drop-Down-listorna i flikarna UPDATE, INSERT och DELETE till (Ingen) (Klicka om du vill visa en bild i full storlek)
När du har slutfört guiden Konfigurera datakälla lägger Visual Studio till ett BoundField för CategoryID
, CategoryName
, Description
, NumberOfProducts
och BrochurePath
. Redigera GridView så att den bara innehåller CategoryName
och Description
BoundFields, och uppdatera CategoryName
BoundField s HeaderText
egenskap till Kategori.
Lägg sedan till ett HyperLinkField och placera det så att det är det vänstra fältet. Ange egenskapen DataNavigateUrlFields
till CategoryID
och egenskapen DataNavigateUrlFormatString
till ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}
. Ange egenskapen Text
till Visa produkter .
Bild 6: Lägg till ett HyperLinkField i Categories
GridView
När du har skapat ObjectDataSource och anpassat GridView-fälten ser de två kontrollernas deklarativa markering ut så här:
<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>
Bild 7 visas Default.aspx
när den visas via en webbläsare. Om du klickar på länken Visa produkter för en kategori går du till ProductsByCategory.aspx?CategoryID=categoryID
, som vi kommer att skapa i steg 3.
Bild 7: Varje kategori visas tillsammans med länken Visa produkter (Klicka om du vill visa en bild i full storlek)
Steg 3: Visa en lista över de valda kategoriprodukterna
Öppna sidan ProductsByCategory.aspx
och lägg till en GridView och namnge den ProductsByCategory
. Från den smarta taggen binder du GridView till en ny ObjectDataSource med namnet ProductsByCategoryDataSource
. Konfigurera ObjectDataSource att använda ProductsBLL
klassens GetProductsByCategoryID(categoryID)
-metod och ange listrutorna till (Ingen) på flikarna UPDATE, INSERT och DELETE.
Bild 8: Använd ProductsBLL
klassens GetProductsByCategoryID(categoryID)
metod (Klicka om du vill visa en bild i full storlek)
Det sista steget i guiden Konfigurera datakälla frågar efter en parameterkälla för categoryID. Eftersom den här informationen skickas via frågesträngsfältet CategoryID
väljer du QueryString i listrutan och anger CategoryID i textrutan QueryStringField enligt bild 9. Klicka på Slutför för att slutföra guiden.
Bild 9: Använd frågesträngsfältet CategoryID
för parametern categoryID (Klicka om du vill visa en bild i full storlek)
När du har slutfört guiden lägger Visual Studio till motsvarande BoundFields och ett CheckBoxField till GridView för produktdatafälten. Ta bort alla utom ProductName
, UnitPrice
och SupplierName
BoundFields. Anpassa dessa tre BoundFields-egenskaper HeaderText
så att de läser Produkt, Pris respektive Leverantör.
UnitPrice
Formatera BoundField som en valuta.
Lägg sedan till ett HyperLinkField och flytta det till den vänstra positionen. Ange dess Text
egenskap till Visa information, dess DataNavigateUrlFields
egenskap till ProductID
och dess DataNavigateUrlFormatString
egenskap till ~/SiteMapProvider/ProductDetails.aspx?ProductID={0}
.
Bild 10: Lägg till en Visa detaljer HyperLinkField som pekar på ProductDetails.aspx
När du har gjort de här anpassningarna bör GridView och ObjectDataSources deklarativa markering likna följande:
<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>
Gå tillbaka till visning Default.aspx
via en webbläsare och klicka på länken Visa produkter för Drycker. Detta tar dig till ProductsByCategory.aspx?CategoryID=1
och visar namn, priser och leverantörer av produkterna i Northwind-databasen som tillhör kategorin Drycker (se bild 11). Du kan förbättra den här sidan ytterligare så att den innehåller en länk för att returnera användare till kategorilistningssidan (Default.aspx
) och en DetailsView- eller FormView-kontroll som visar den valda kategorins namn och beskrivning.
Bild 11: Dryckernas namn, priser och leverantörer visas (Klicka om du vill visa en bild i full storlek)
Steg 4: Visa information om en produkt
Den sista sidan, ProductDetails.aspx
, visar den valda produktinformationen. Öppna ProductDetails.aspx
och dra en DetailsView från Verktygslådan till Designern. Ange egenskapen ID
för DetailsView till ProductInfo
och rensa värdena för dess egenskaper Height
och Width
. Från den smarta taggen binder du DetailsView till en ny ObjectDataSource med namnet ProductDataSource
och konfigurerar ObjectDataSource för att hämta data från ProductsBLL
klassens GetProductByProductID(productID)
-metod. Precis som med föregående webbsidor som skapades i steg 2 och 3 anger du listrutorna i flikarna UPPDATERA, INFOGA och TA BORT till (Ingen) .
Bild 12: Konfigurera ObjectDataSource att använda GetProductByProductID(productID)
metoden (Klicka om du vill visa en bild i full storlek)
Det sista steget i guiden Konfigurera datakälla frågar efter källan för parametern productID . Eftersom dessa data kommer via frågesträngsfältet ProductID
, ställer du in listrutan på QueryString och textrutan QueryStringField på ProductID. Klicka slutligen på knappen Slutför för att slutföra guiden.
Bild 13: Konfigurera productID-parametern för att hämta dess värde från frågesträngsfältet ProductID
(Klicka om du vill visa en bild i full storlek)
När du har slutfört guiden Konfigurera datakälla skapar Visual Studio motsvarande BoundFields och ett CheckBoxField i DetailsView för produktdatafälten. Ta bort ProductID
, SupplierID
och CategoryID
BoundFields och konfigurera de kvarvarande fälten efter behov. Efter en handfull estetiska konfigurationer såg min DetailsView och ObjectDataSources deklarativa markering ut så här:
<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>
Om du vill testa den här sidan går du tillbaka till Default.aspx
och klickar på Visa produkter för kategorin Drycker. Från listan över dryckesprodukter klickar du på länken Visa information för Chai Tea. Detta tar dig till ProductDetails.aspx?ProductID=1
, som visar detaljerna om en Chai-te (se bild 14).
Bild 14: Chai Teas Leverantör, Kategori, Pris och Annan information visas (Klicka om du vill visa en bild i full storlek)
Steg 5: Förstå det inre arbetet hos en webbplatsöversiktsprovider
Webbplatskartan representeras i webbserverns minne som en samling SiteMapNode
instanser som utgör en hierarki. Det måste finnas exakt en rot, alla icke-rotnoder måste ha exakt en överordnad nod och alla noder kan ha ett godtyckligt antal underordnade. Varje SiteMapNode
objekt representerar ett avsnitt i webbplatsens struktur. Dessa avsnitt har vanligtvis en motsvarande webbsida. Klassen har därförSiteMapNode
egenskaper som Title
, Url
och Description
, som ger information för avsnittet som SiteMapNode
representerar. Det finns också en egenskap som unikt identifierar var och en Key
i hierarkin, samt egenskaper som används för att upprätta den här hierarkin SiteMapNode
, ChildNodes
, ParentNode
, NextSibling
och så PreviousSibling
vidare.
Bild 15 visar den allmänna webbplatskartstrukturen från bild 1, men med implementeringsinformationen skissad i detalj.
Bild 15: Var och en SiteMapNode
har egenskaper som Title
, Url
, Key
och Så vidare (Klicka om du vill visa en bild i full storlek)
Webbplatsöversikten SiteMap
är tillgänglig via klassen i System.Web
namnområdet. Den här klassens RootNode
egenskap returnerar platskartans rotinstans SiteMapNode
. CurrentNode
Returnerar den SiteMapNode
vars Url
egenskap matchar URL:en för den begärda sidan. Den här klassen används internt av ASP.NET 2.0-navigeringswebbkontroller.
SiteMap
När klassens egenskaper används måste den serialisera webbplatsöversiktsstrukturen från ett beständigt medium till minnet. Platskartans serialiseringslogik är dock inte hårdkodad i SiteMap
klassen. Istället avgör klassen vid körning vilken SiteMap
som ska användas för serialisering. Som standard XmlSiteMapProvider
används klassen , som läser webbplatskartans struktur från en korrekt formaterad XML-fil. Men med lite arbete kan vi skapa en egen anpassad webbplatsöversiktsleverantör.
Alla webbplatskartproviders måste härledas från SiteMapProvider
-klassen, vilket inkluderar de viktiga metoder och egenskaper som krävs för webbplatskartproviders, men utelämnar många av implementeringsdetaljerna. En andra klass, StaticSiteMapProvider
, utökar SiteMapProvider
klassen och innehåller en mer robust implementering av nödvändiga funktioner. Internt StaticSiteMapProvider
lagrar SiteMapNode
instanserna av webbplatskartan i en Hashtable
och tillhandahåller metoder som AddNode(child, parent)
, RemoveNode(siteMapNode),
och Clear()
som lägger till och tar bort SiteMapNode
s i den interna Hashtable
.
XmlSiteMapProvider
härleds från StaticSiteMapProvider
.
När du skapar en anpassad webbplatsöversiktsprovider som utökar StaticSiteMapProvider
finns det två abstrakta metoder som måste åsidosättas: BuildSiteMap
och GetRootNodeCore
.
BuildSiteMap
, som namnet antyder, ansvarar för att läsa in webbplatskartans struktur från beständig lagring och konstruera den i minnet.
GetRootNodeCore
returnerar rotnoden på platskartan.
Innan ett webbprogram kan använda en webbplatsöversiktsprovider måste det registreras i programmets konfiguration. Som standard registreras klassen XmlSiteMapProvider
med namnet AspNetXmlSiteMapProvider
. För att registrera ytterligare sitemap-leverantörer, lägg till följande markup i Web.config
:
<configuration>
<system.web>
...
<siteMap defaultProvider="defaultProviderName">
<providers>
<add name="name" type="type" />
</providers>
</siteMap>
</system.web>
</configuration>
Namnvärdet tilldelar ett läsbart namn till providern medan typen anger webbplatsöversiktsproviderns fullständigt kvalificerade typnamn. Vi utforskar konkreta värden för namn och typ i Steg 7, efter att vi har skapat vår anpassade webbplatskarta leverantör.
Webbplatskartans providerklass instansieras första gången den nås från SiteMap
-klassen och förblir i minnet under hela webbprogrammets livslängd. Eftersom det bara finns en instans av sitemap-leverantören som kan anropas från flera samtidiga webbplatsbesökare är det absolut nödvändigt att leverantörens methoder är trådsäkra.
Av prestanda- och skalbarhetsskäl är det viktigt att vi cachelagra den minnesinterna webbplatsöversiktsstrukturen och returnerar den cachelagrade strukturen i stället för att återskapa den BuildSiteMap
varje gång metoden anropas.
BuildSiteMap
kan anropas flera gånger per sidbegäran per användare, beroende på vilka navigeringskontroller som används på sidan och djupet i webbplatskartans struktur. Om vi i vilket fall som helst inte cachelagr webbplatsöversiktsstrukturen BuildSiteMap
varje gång den anropas måste vi hämta produkt- och kategoriinformationen igen från arkitekturen (vilket skulle resultera i en fråga till databasen). Som vi diskuterade i de tidigare självstudierna för cachelagring kan cachelagrade data bli inaktuella. För att bekämpa detta kan vi använda antingen tids- eller SQL-cacheberoendebaserade förfallodatum.
Anmärkning
En webbplatsöversiktsprovider kan eventuellt åsidosätta Initialize
metoden.
Initialize
anropas när sitemap-providern först instansieras och får de anpassade attribut som tilldelats providern i Web.config
-elementet <add>
, såsom: <add name="name" type="type" customAttribute="value" />
. Det är användbart om du vill tillåta att en sidutvecklare anger olika providerrelaterade inställningar för webbplatskartan utan att behöva ändra providerns kod. Om vi till exempel läste kategori- och produktdata direkt från databasen i stället för via arkitekturen, skulle vi förmodligen vilja låta sidutvecklaren ange databasanslutningssträngen i Web.config
stället för att använda ett hårdkodat värde i providerkoden. Den anpassade webbplatsöversiktsprovidern som vi skapar i steg 6 åsidosätter inte den här Initialize
metoden. Ett exempel på hur du använder metoden finns i Initialize
artikeln Jeff Prosise s Storing Site Maps in SQL Server .
Steg 6: Skapa en anpassad sajtöversiktshanterare
Om du vill skapa en anpassad webbplatsöversiktsprovider som skapar webbplatskartan från kategorierna och produkterna i Northwind-databasen måste vi skapa en klass som utökar StaticSiteMapProvider
. I steg 1 bad jag dig att lägga till en CustomProviders
mapp i App_Code
mappen – lägg till en ny klass i den här mappen med namnet NorthwindSiteMapProvider
. Lägg till följande kod i NorthwindSiteMapProvider
klassen:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.Caching;
public class NorthwindSiteMapProvider : StaticSiteMapProvider
{
private readonly object siteMapLock = new object();
private SiteMapNode root = null;
public const string CacheDependencyKey =
"NorthwindSiteMapProviderCacheDependency";
public override SiteMapNode BuildSiteMap()
{
// Use a lock to make this method thread-safe
lock (siteMapLock)
{
// First, see if we already have constructed the
// rootNode. If so, return it...
if (root != null)
return root;
// We need to build the site map!
// Clear out the current site map structure
base.Clear();
// Get the categories and products information from the database
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = productsAPI.GetProducts();
// Create the root SiteMapNode
root = new SiteMapNode(
this, "root", "~/SiteMapProvider/Default.aspx", "All Categories");
AddNode(root);
// Create SiteMapNodes for the categories and products
foreach (Northwind.ProductsRow product in products)
{
// Add a new category SiteMapNode, if needed
string categoryKey, categoryName;
bool createUrlForCategoryNode = true;
if (product.IsCategoryIDNull())
{
categoryKey = "Category:None";
categoryName = "None";
createUrlForCategoryNode = false;
}
else
{
categoryKey = string.Concat("Category:", product.CategoryID);
categoryName = product.CategoryName;
}
SiteMapNode categoryNode = FindSiteMapNodeFromKey(categoryKey);
// Add the category SiteMapNode if it does not exist
if (categoryNode == null)
{
string productsByCategoryUrl = string.Empty;
if (createUrlForCategoryNode)
productsByCategoryUrl =
"~/SiteMapProvider/ProductsByCategory.aspx?CategoryID="
+ product.CategoryID;
categoryNode = new SiteMapNode(
this, categoryKey, productsByCategoryUrl, categoryName);
AddNode(categoryNode, root);
}
// Add the product SiteMapNode
string productUrl =
"~/SiteMapProvider/ProductDetails.aspx?ProductID="
+ product.ProductID;
SiteMapNode productNode = new SiteMapNode(
this, string.Concat("Product:", product.ProductID),
productUrl, product.ProductName);
AddNode(productNode, categoryNode);
}
// Add a "dummy" item to the cache using a SqlCacheDependency
// on the Products and Categories tables
System.Web.Caching.SqlCacheDependency productsTableDependency =
new System.Web.Caching.SqlCacheDependency("NorthwindDB", "Products");
System.Web.Caching.SqlCacheDependency categoriesTableDependency =
new System.Web.Caching.SqlCacheDependency("NorthwindDB", "Categories");
// Create an AggregateCacheDependency
System.Web.Caching.AggregateCacheDependency aggregateDependencies =
new System.Web.Caching.AggregateCacheDependency();
aggregateDependencies.Add(productsTableDependency, categoriesTableDependency);
// Add the item to the cache specifying a callback function
HttpRuntime.Cache.Insert(
CacheDependencyKey, DateTime.Now, aggregateDependencies,
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
CacheItemPriority.Normal,
new CacheItemRemovedCallback(OnSiteMapChanged));
// Finally, return the root node
return root;
}
}
protected override SiteMapNode GetRootNodeCore()
{
return BuildSiteMap();
}
protected void OnSiteMapChanged(string key, object value, CacheItemRemovedReason reason)
{
lock (siteMapLock)
{
if (string.Compare(key, CacheDependencyKey) == 0)
{
// Refresh the site map
root = null;
}
}
}
public DateTime? CachedDate
{
get
{
return HttpRuntime.Cache[CacheDependencyKey] as DateTime?;
}
}
}
Låt oss börja med att utforska den här klassens BuildSiteMap
metod, som börjar med en lock
-instruktion. Instruktionen lock
tillåter endast en tråd i taget att ange, vilket serialiserar åtkomsten till koden och förhindrar att två samtidiga trådar trampar på varandras tår.
På klassnivå används variabeln SiteMapNode
för att cachelagra sajtkartans struktur. När webbplatsöversikten byggs för första gången, eller för första gången efter att den underliggande datan har ändrats, kommer root
att vara null
och platskartans struktur kommer att konstrueras. Platskartans rotnod tilldelas root
under byggprocessen så att nästa gång den här metoden anropas, kommer root
inte att vara null
. Så länge root
inte är null
, kommer webbplatskartans struktur att returneras till anroparen utan att behöva återskapas.
Om roten är null
skapas webbplatsöversiktsstrukturen från produkt- och kategoriinformationen. Webbplatskartan skapas genom att skapa SiteMapNode
instanserna och sedan bilda hierarkin genom anrop till StaticSiteMapProvider
klassens AddNode
-metod.
AddNode
utför den interna bokföringen och lagrar de olika SiteMapNode
instanserna i en Hashtable
. Innan vi börjar skapa hierarkin börjar vi med att anropa Clear
metoden som rensar ut elementen från den interna Hashtable
.
ProductsBLL
Därefter lagras klassens GetProducts
metod och resultatet ProductsDataTable
i lokala variabler.
Webbplatskartans konstruktion börjar med att skapa rotnoden och tilldela den till root
. Överlagringen av konstruktornSiteMapNode
som används här och i det här BuildSiteMap
sammanhanget skickas följande information:
- En referens till webbplatsöversiktsprovidern (
this
). -
SiteMapNode
sKey
. Det här obligatoriska värdet måste vara unikt för varjeSiteMapNode
. -
SiteMapNode
sUrl
.Url
är valfritt, men om det anges måste varjeSiteMapNode
värdeUrl
vara unikt. - s
SiteMapNode
Title
, som krävs.
Metodanropet AddNode(root)
lägger till SiteMapNode
root
till webbplatskartan som roten. Nästa, varje ProductRow
i ProductsDataTable
räknas upp. Om det redan finns en SiteMapNode
för den aktuella produktkategorin refereras den till. Annars skapas en ny SiteMapNode
för kategorin och läggs som underordnad till SiteMapNode``root
genom metodanropet AddNode(categoryNode, root)
. När lämplig kategorinod SiteMapNode
har hittats eller skapats skapas en SiteMapNode
för den aktuella produkten och läggs till som underordnad i kategorin SiteMapNode
via AddNode(productNode, categoryNode)
. Observera att kategorins SiteMapNode
egenskapsvärde Url
är ~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID
när produktegenskapen SiteMapNode
tilldelas Url
~/SiteMapNode/ProductDetails.aspx?ProductID=productID
.
Anmärkning
De produkter som har ett databasvärde NULL
för sina CategoryID
grupperas under en kategori SiteMapNode
vars Title
egenskap är inställd på Ingen och vars Url
egenskap är inställd på en tom sträng. Jag bestämde mig för att ställa in Url
på en tom sträng eftersom ProductBLL
klassens GetProductsByCategory(categoryID)
metod för närvarande saknar möjligheten att returnera bara de produkter med ett NULL
CategoryID
värde. Dessutom ville jag visa hur navigeringskontrollerna återge en SiteMapNode
som saknar ett värde för sin Url
egenskap. Jag rekommenderar att du utökar den här handledningen så att egenskapen None SiteMapNode
Url
pekar på ProductsByCategory.aspx
, men bara visar produkterna med NULL
CategoryID
värdena.
När du har skapat webbplatsöversikten läggs ett godtyckligt objekt till i datacachen med hjälp av ett SQL-cacheberoende för tabellerna Categories
och Products
via ett AggregateCacheDependency
objekt. Vi utforskade att använda SQL Cache-beroenden i föregående självstudie, Använda SQL Cache-beroenden. Den anpassade webbplatsöversiktsprovidern använder dock en överbelastning av datacachens Insert
metod som vi ännu inte har utforskat. Den här överbelastningen accepterar en delegering som sin sista indataparameter, vilken anropas när objektet tas bort från cacheminnet. Mer specifikt skickar vi in ett nytt CacheItemRemovedCallback
ombud som pekar på metoden OnSiteMapChanged
som definieras längre ned i NorthwindSiteMapProvider
klassen.
Anmärkning
Minnesintern representation av platskartan cachelagras via variabeln root
på klassnivå . Eftersom det bara finns en instans av den anpassade webbplatskartans providerklass och eftersom den instansen delas mellan alla trådar i webbprogrammet fungerar den här klassvariabeln som en cache. Metoden BuildSiteMap
använder också datacachen, men bara som ett sätt att ta emot meddelanden när underliggande databasdata i tabellerna Categories
eller Products
ändras. Observera att värdet som placeras i datacachen bara är aktuellt datum och tid. De faktiska webbplatsöversiktsdata placeras inte i datacachen.
Metoden BuildSiteMap
slutförs genom att returnera rotnoden för platskartan.
De återstående metoderna är ganska enkla.
GetRootNodeCore
ansvarar för att returnera rotnoden. Eftersom BuildSiteMap
returnerar roten GetRootNodeCore
returnerar BuildSiteMap
bara returvärdet. Metoden OnSiteMapChanged
återgår root
till null
när cacheobjektet tas bort. När roten har återställts till null
, kommer platskartan att byggas om nästa gång BuildSiteMap
anropas. Slutligen CachedDate
returnerar egenskapen det datum- och tidsvärde som lagras i datacachen, om det finns ett sådant värde. Den här egenskapen kan användas av en sidutvecklare för att avgöra när webbplatsöversiktsdata senast cachelagrades.
Steg 7: Registrera NorthwindSiteMapProvider
För att vår webbapp ska kunna använda webbplatsöversiktsprovidern NorthwindSiteMapProvider
som skapades i steg 6 måste vi registrera den <siteMap>
i avsnittet Web.config
. Mer specifikt lägger du till följande markering i elementet <system.web>
i Web.config
:
<siteMap defaultProvider="AspNetXmlSiteMapProvider">
<providers>
<add name="Northwind" type="NorthwindSiteMapProvider" />
</providers>
</siteMap>
Den här markeringen gör två saker: för det första anger den att den inbyggda AspNetXmlSiteMapProvider
är standardprovidern för webbplatskartor. För det andra registrerar den anpassade webbplatskartaprovidern som skapades i steg 6 med det människovänliga namnet Northwind .
Anmärkning
För webbplatsöversiktsprovidrar som finns i programmets App_Code
mapp är värdet för type
attributet helt enkelt klassnamnet. Alternativt kan den anpassade webbplatsöversiktsprovidern ha skapats i ett separat klassbiblioteksprojekt med den kompilerade sammansättningen placerad i webbprogrammets /Bin
katalog. I så fall type
skulle attributvärdet vara Namnområde.ClassName, AssemblyName .
När du har uppdaterat Web.config
, ta en stund för att visa vilken sida som helst från handledningarna i en webbläsare. Observera att navigeringsgränssnittet till vänster fortfarande visar de avsnitt och handledningar som definierats i Web.sitemap
. Det beror på att vi lämnade AspNetXmlSiteMapProvider
som standardprovider. För att kunna skapa ett navigeringsgränssnittselement som använder NorthwindSiteMapProvider
måste vi uttryckligen ange att northwind-webbplatsöversiktsprovidern ska användas. Vi får se hur du gör detta i steg 8.
Steg 8: Visa webbplatsöversiktsinformation med hjälp av den anpassade webbplatsöversiktsprovidern
När den anpassade webbplatsöversiktsprovidern har skapats och registrerats i Web.config
är vi redo att lägga till navigeringskontroller till Default.aspx
sidorna , ProductsByCategory.aspx
och ProductDetails.aspx
i SiteMapProvider
mappen. Börja med att öppna sidan Default.aspx
och dra en SiteMapPath
från verktygslådan till designern. Kontrollen SiteMapPath finns i avsnittet Navigering i verktygslådan.
Bild 16: Lägg till en SiteMapPath i Default.aspx
(Klicka om du vill visa en bild i full storlek)
Kontrollen SiteMapPath visar en sökväg som anger den aktuella sidans plats på webbplatskartan. Vi har lagt till en SiteMapPath överst på master page i handledningen Huvudsidor och Webbplatsnavigering.
Ta en stund och titta på den här sidan via en webbläsare. SiteMapPath som lades till i bild 16 använder standardprovidern för webbplatskartor och hämtar sina data från Web.sitemap
. Därför visar brödsmulan Hem > Anpassa webbplatskartan, precis som brödsmulan i det övre högra hörnet.
Bild 17: Breadcrumb använder standardprovidern för webbplatskartor (Klicka om du vill visa en bild i full storlek)
Om du vill att SiteMapPath ska läggas till i bild 16 använder du den anpassade webbplatsöversiktsprovidern som vi skapade i steg 6. Ange dessSiteMapProvider
egenskap till Northwind, namnet som vi tilldelade i NorthwindSiteMapProvider
Web.config
. Tyvärr fortsätter designern att använda standardprovidern för webbplatsöversikt, men om du besöker sidan via en webbläsare när du har gjort den här egenskapsändringen ser du att sökvägsuppsättningen nu använder den anpassade webbplatskartprovidern.
Bild 18: Breadcrumb använder nu den anpassade webbplatskartleverantören NorthwindSiteMapProvider
(klicka för att visa bilden i full storlek)
Kontrollen SiteMapPath visar ett mer funktionellt användargränssnitt på ProductsByCategory.aspx
sidorna och ProductDetails.aspx
. Lägg till en SiteMapPath på dessa sidor och ställ in SiteMapProvider
-egenskapen till Northwind i båda. Klicka Default.aspx
på länken Visa produkter för Drycker och sedan på länken Visa information för Chai Tea. Som bild 19 visar innehåller navigationsstigen det aktuella avsnittet av webbplatskartan (Chai Tea) och dess överordnade kategorier: Drycker och Alla kategorier.
Bild 19: Breadcrumb använder nu den anpassade webbplatskarteprovidern NorthwindSiteMapProvider
(klicka om du vill visa en bild i full storlek)
Andra gränssnittselement för navigeringsanvändare kan användas utöver SiteMapPath, till exempel kontrollerna Meny och TreeView. Sidorna Default.aspx
, ProductsByCategory.aspx
och ProductDetails.aspx
i nedladdningen för den här självstudien inkluderar, till exempel, alla menykontroller (se bild 20). Se ASP.NET 2.0:s avancerade webbplatsnavigeringsfunktioner och avsnittet Använda platsnavigeringskontroller i snabbstarterna ASP.NET 2.0 för en mer djupgående titt på navigeringskontrollerna och platskartsystemet i ASP.NET 2.0.
Bild 20: Menykontrollen visar var och en av kategorierna och produkterna (klicka om du vill visa en bild i full storlek)
Som tidigare nämnts i den här självstudien kan webbplatskartstrukturen nås programmatiskt via SiteMap
klassen. Följande kod returnerar standardproviderns rot SiteMapNode
:
SiteMapNode root = SiteMap.RootNode;
Eftersom AspNetXmlSiteMapProvider
är standardprovidern för vårt program, skulle koden ovan returnera rotnoden som definierats i Web.sitemap
. Om du vill referera till en annan webbplatskartleverantör än standardvärdet använder du SiteMap
klassensProviders
egenskap så här:
SiteMapNode root = SiteMap.Providers["name"].RootNode;
Där namnet är namnet på den anpassade webbplatsöversiktsprovidern ( Northwind, för vårt webbprogram).
För att komma åt en medlem som är specifik för en sitemap-leverantör, använd SiteMap.Providers["name"]
för att hämta leverantörsinstansen och omvandla den sedan till rätt typ. Om du till exempel vill visa NorthwindSiteMapProvider
egenskapen s CachedDate
på en ASP.NET-sida använder du följande kod:
NorthwindSiteMapProvider customProvider =
SiteMap.Providers["Northwind"] as NorthwindSiteMapProvider;
if (customProvider != null)
{
DateTime? lastCachedDate = customProvider.CachedDate;
if (lastCachedDate != null)
LabelID.Text = "Site map cached on: " + lastCachedDate.Value.ToString();
else
LabelID.Text = "The site map is being reconstructed!";
}
Anmärkning
Se till att testa sql-cacheberoendefunktionen. När du har besökt Default.aspx
sidorna, ProductsByCategory.aspx
och ProductDetails.aspx
går du till en av handledningarna i avsnittet Redigera, Infoga och Ta bort och ändrar namnet på en kategori eller produkt. Gå sedan tillbaka till en av sidorna i SiteMapProvider
mappen. Om det har gått tillräckligt med tid för avsökningsmekanismen att notera ändringen av den underliggande databasen, bör webbplatskartan uppdateras för att visa det nya produkt- eller kategorinamnet.
Sammanfattning
ASP.NET webbplatsöversiktsfunktioner på 2,0 s innehåller en SiteMap
klass, ett antal inbyggda navigeringswebbkontroller och en standardleverantör för webbplatsöversikt som förväntar sig att webbplatsöversiktsinformationen sparas i en XML-fil. För att kunna använda webbplatsöversiktsinformation från någon annan källa, till exempel från en databas, programmets arkitektur eller en fjärrwebbtjänst, måste vi skapa en anpassad webbplatsöversiktsprovider. Det innebär att skapa en klass som direkt eller indirekt härleds från SiteMapProvider
klassen.
I den här handledningen har vi sett hur du skapar en anpassad webbplatskartleverantör som baserar webbplatskartan på produkt- och kategoriinformation som har hämtats från programarkitekturen. Vår provider utökade StaticSiteMapProvider
klassen och innebar att skapa en BuildSiteMap
metod som hämtade data, konstruerade platskartehierarkin och cachelagrade den resulterande strukturen i en variabel på klassnivå. Vi använde ett SQL-cacheberoende med en återanropsfunktion för att ogiltigförklara den cachelagrade strukturen när underliggande Categories
data eller Products
data ändras.
Lycka till med programmerandet!
Ytterligare läsning
Mer information om de ämnen som beskrivs i den här självstudien finns i följande resurser:
- Lagra webbplatskartor i SQL Server och Den SQL-webbplatskartsleverantören du har väntat på
- Providerverktyget
- ASP.NET 2.0:s avancerade webbplatsnavigeringsfunktioner
Om författaren
Scott Mitchell, författare till sju ASP/ASP.NET-böcker och grundare av 4GuysFromRolla.com, har arbetat med Microsofts webbtekniker sedan 1998. Scott arbetar som oberoende konsult, tränare och författare. Hans senaste bok är Sams Teach Yourself ASP.NET 2.0 på 24 timmar. Han kan nås på mitchell@4GuysFromRolla.com.
Särskilt tack till
Den här självstudieserien granskades av många användbara granskare. Huvudgranskare för den här självstudien var Dave Gardner, Zack Jones, Teresa Murphy och Bernadette Leigh. Vill du granska mina kommande MSDN-artiklar? Om så är fallet, hör av dig på mitchell@4GuysFromRolla.com.