Beruflich Dokumente
Kultur Dokumente
NETintheWorkingwithData
inASP.NET2.0sectionoftheASP.NETsiteathttp://www.asp.net/learn/dataaccess/default.aspx.
WorkingwithDatainASP.NET2.0::Buildinga
CustomDatabaseDrivenSiteMapProvider
Introduction
ASP.NET2.0ssitemapfeatureenablesapagedevelopertodefineawebapplicationssitemapinsomepersistent
medium,suchasinanXMLfile.Oncedefined,thesitemapdatacanbeaccessedprogrammaticallythroughthe
SiteMap class inthe System.Web namespaceorthroughavarietyofnavigationWebcontrols,suchasthe
SiteMapPath,Menu,andTreeViewcontrols.Thesitemapsystemusesthe providermodel sothatdifferentsite
mapserializationimplementationscanbecreatedandpluggedintoawebapplication.Thedefaultsitemap
providerthatshipswithASP.NET2.0persistssitemapstructureinanXMLfile.BackintheMasterPagesandSite
Navigation tutorialwecreatedafilenamedWeb.sitemap thatcontainedthisstructureandhavebeenupdatingits
XMLwitheachnewtutorialsection.
ThedefaultXMLbasedsitemapproviderworkswellifthesitemapsstructureisfairlystatic,suchasforthese
tutorials.Inmanyscenarios,however,amoredynamicsitemapisneeded.ConsiderthesitemapshowninFigure
1,whereeachcategoryandproductappearassectionsinthewebsitesstructure.Withthissitemap,visitingthe
webpagecorrespondingtotherootnodemightlistallofthecategories,whereasvisitingaparticularcategorys
webpagewouldlistthatcategorysproductsandviewingaparticularproductswebpagewouldshowthat
productsdetails.
Figure1:TheCategoriesandProductsMakeuptheSiteMapsStructure
1 of26
Note:Thecustomsitemapprovidercreatedinthistutorialistightlycoupledtotheapplicationsarchitecture
anddatamodel.JeffProsisesStoringSiteMapsinSQLServerandTheSQLSiteMapProviderYouve
BeenWaitingFor articlesexamineageneralizedapproachtostoringsitemapdatainSQLServer.
Step1:CreatingtheCustomSiteMapProviderWebPages
Beforewestartcreatingacustomsitemapprovider,letsfirstaddtheASP.NETpageswellneedforthistutorial.
StartbyaddinganewfoldernamedSiteMapProvider.Next,addthefollowingASP.NETpagestothatfolder,
makingsuretoassociateeachpagewiththeSite.master masterpage:
Default.aspx
ProductsByCategory.aspx
l ProductDetails.aspx
l
l
2 of26
Figure2:AddtheASP.NETPagesfortheSiteMapProviderRelatedTutorials
AfterupdatingWeb.sitemap,takeamomenttoviewthetutorialswebsitethroughabrowser.Themenuontheleft
3 of26
nowincludesanitemforthesolesitemapprovidertutorial.
Figure3:TheSiteMapNowIncludesanEntryfortheSiteMapProviderTutorial
Thistutorialsmainfocusistoillustratecreatingacustomsitemapproviderandconfiguringawebapplicationto
usethatprovider.Inparticular,wellbuildaproviderthatreturnsasitemapthatincludesarootnodealongwitha
nodeforeachcategoryandproduct,asdepictedinFigure1.Ingeneral,eachnodeinthesitemapmayspecifya
URL.Foroursitemap,therootnodesURLwillbe~/SiteMapProvider/Default.aspx,whichwilllistallofthe
categoriesinthedatabase.EachcategorynodeinthesitemapwillhaveaURLthatpointsto
~/SiteMapProvider/ProductsByCategory.aspx?CategoryID=categoryID,whichwilllistalloftheproductsin
thespecified categoryID.Finally,eachproductsitemapnodewillpointto
~/SiteMapProvider/ProductDetails.aspx?ProductID=productID,whichwilldisplaythespecificproducts
details.
TostartweneedtocreatetheDefault.aspx,ProductsByCategory.aspx,andProductDetails.aspx pages.
ThesepagesarecompletedinSteps2,3,and4,respectively.Sincethethrustofthistutorialisonsitemap
providers,andsincepasttutorialshavecoveredcreatingthesesortsofmultipagemaster/detailreports,wewill
hurrythroughSteps2through4.Ifyouneedarefresheroncreatingmaster/detailreportsthatspanmultiplepages,
referbacktothe Master/DetailFilteringAcrossTwoPagestutorial.
Step2:DisplayingaListofCategories
OpentheDefault.aspx pageintheSiteMapProvider folderanddragaGridViewfromtheToolboxontothe
Designer,settingitsID toCategories.FromtheGridViewssmarttag,bindittoanewObjectDataSourcenamed
CategoriesDataSource andconfigureitsothatitretrievesitsdatausingtheCategoriesBLL classs
GetCategories method.SincethisGridViewjustdisplaysthecategoriesanddoesnotprovidedatamodification
capabilities,setthedropdownlistsintheUPDATE,INSERT,andDELETEtabsto(None).
4 of26
Figure4:ConfiguretheObjectDataSourcetoReturnCategoriesUsingtheGetCategories Method
5 of26
Figure5:SettheDropDownListsintheUPDATE,INSERT,andDELETETabsto(None)
AftercompletingtheConfigureDataSourcewizard,VisualStudiowilladdaBoundFieldforCategoryID,
CategoryName,Description,NumberOfProducts,andBrochurePath.EdittheGridViewsothatitonlycontains
theCategoryName andDescription BoundFieldsandupdatetheCategoryName BoundFieldsHeaderText
propertytoCategory.
Next,addaHyperLinkFieldandpositionitsothatitstheleftmostfield.SettheDataNavigateUrlFields
propertytoCategoryID andtheDataNavigateUrlFormatString propertyto
~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}.SettheText propertytoViewProducts.
6 of26
Figure6:AddaHyperLinkFieldtotheCategories GridView
AftercreatingtheObjectDataSourceandcustomizingtheGridViewsfields,thetwocontrols declarativemarkup
willlooklikethefollowing:
<asp:GridViewID="Categories"runat="server"AutoGenerateColumns="False"
DataKeyNames="CategoryID"DataSourceID="CategoriesDataSource"
EnableViewState="False">
<Columns>
<asp:HyperLinkFieldDataNavigateUrlFields="CategoryID"
DataNavigateUrlFormatString=
"~/SiteMapProvider/ProductsByCategory.aspx?CategoryID={0}"
Text="ViewProducts"/>
<asp:BoundFieldDataField="CategoryName"HeaderText="Category"
SortExpression="CategoryName"/>
<asp:BoundFieldDataField="Description"HeaderText="Description"
SortExpression="Description"/>
</Columns>
</asp:GridView>
<asp:ObjectDataSourceID="CategoriesDataSource"runat="server"
OldValuesParameterFormatString="original_{0}"SelectMethod="GetCategories"
TypeName="CategoriesBLL"></asp:ObjectDataSource>
Figure7showsDefault.aspx whenviewedthroughabrowser.ClickingacategorysViewProductslinktakes
youtoProductsByCategory.aspx?CategoryID=categoryID,whichwewillbuildinStep3.
7 of26
Figure7:EachCategoryisListedAlongwithaViewProductsLink
Step3:ListingtheSelectedCategorysProducts
OpentheProductsByCategory.aspx pageandaddaGridView,namingit ProductsByCategory.Fromitssmart
tag,bindtheGridViewtoanewObjectDataSourcenamedProductsByCategoryDataSource.Configurethe
ObjectDataSourcetousetheProductsBLL classsGetProductsByCategoryID(categoryID) methodandsetthe
dropdownliststo(None)intheUPDATE,INSERT,andDELETEtabs.
8 of26
ThefinalstepintheConfigureDataSourcewizardpromptsforaparametersourcefor categoryID.Sincethis
informationispassedthroughthequerystringfieldCategoryID,selectQueryStringfromthedropdownlistand
enter CategoryIDintheQueryStringFieldtextboxasshowninFigure9.ClickFinishtocompletethewizard.
9 of26
Figure9:UsetheCategoryID QuerystringFieldforthecategoryIDParameter
Aftercompletingthewizard,VisualStudiowilladdcorrespondingBoundFieldsandaCheckBoxFieldtothe
GridViewfortheproductdatafields.RemoveallbuttheProductName,UnitPrice,andSupplierName
BoundFields.CustomizethesethreeBoundFieldsHeaderText propertiestoreadProduct, Price, and
Supplier,respectively.FormattheUnitPrice BoundFieldasacurrency.
Next,addaHyperLinkFieldandmoveittotheleftmostposition.SetitsText propertytoViewDetails, its
DataNavigateUrlFields propertytoProductID,anditsDataNavigateUrlFormatString propertyto
~/SiteMapProvider/ProductDetails.aspx?ProductID={0}.
10 of26
Figure10:AddaViewDetailsHyperLinkFieldthatPointstoProductDetails.aspx
Aftermakingthesecustomizations,theGridViewandObjectDataSourcesdeclarativemarkupshouldresemblethe
following:
<asp:GridViewID="ProductsByCategory"runat="server"AutoGenerateColumns="False"
DataKeyNames="ProductID"DataSourceID="ProductsByCategoryDataSource"
EnableViewState="False">
<Columns>
<asp:HyperLinkFieldDataNavigateUrlFields="ProductID"
DataNavigateUrlFormatString=
"~/SiteMapProvider/ProductDetails.aspx?ProductID={0}"
Text="ViewDetails"/>
<asp:BoundFieldDataField="ProductName"HeaderText="Product"
SortExpression="ProductName"/>
<asp:BoundFieldDataField="UnitPrice"DataFormatString="{0:c}"
HeaderText="Price"HtmlEncode="False"
SortExpression="UnitPrice"/>
<asp:BoundFieldDataField="SupplierName"HeaderText="Supplier"
ReadOnly="True"SortExpression="SupplierName"/>
</Columns>
</asp:GridView>
<asp:ObjectDataSourceID="ProductsByCategoryDataSource"runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProductsByCategoryID"TypeName="ProductsBLL">
<SelectParameters>
<asp:QueryStringParameterName="categoryID"
11 of26
QueryStringField="CategoryID"Type="Int32"/>
</SelectParameters>
</asp:ObjectDataSource>
ReturntoviewingDefault.aspx throughabrowserandclickontheViewProductslinkforBeverages.This
willtakeyoutoProductsByCategory.aspx?CategoryID=1,displayingthenames,prices,andsuppliersofthe
productsintheNorthwinddatabasethatbelongtotheBeveragescategory(seeFigure11).Feelfreetofurther
enhancethispagetoincludealinktoreturnuserstothecategorylistingpage(Default.aspx)andaDetailsView
orFormViewcontrolthatdisplaystheselectedcategorysnameanddescription.
Figure11:TheBeverages Names,Prices,andSuppliersareDisplayed
Step4:ShowingaProductsDetails
Thefinalpage,ProductDetails.aspx,displaystheselectedproductsdetails.Open ProductDetails.aspx and
dragaDetailsViewfromtheToolboxontotheDesigner.SettheDetailsViewsID propertytoProductInfo and
clearoutitsHeight andWidth propertyvalues.Fromitssmarttag,bindtheDetailsViewtoanew
ObjectDataSourcenamedProductDataSource,configuringtheObjectDataSourcetopullitsdatafromthe
ProductsBLL classsGetProductByProductID(productID) method.Aswiththepreviouswebpagescreatedin
Steps2and3,setthedropdownlistsintheUPDATE,INSERT,andDELETEtabsto (None).
12 of26
Figure12:ConfiguretheObjectDataSourcetoUsetheGetProductByProductID(productID) Method
ThelaststepoftheConfigureDataSourcewizardpromptsforthesourceofthe productIDparameter.Sincethis
datacomesthroughthequerystringfieldProductID,setthedropdownlisttoQueryStringandthe
QueryStringFieldtextboxto ProductID. Finally,clicktheFinishbuttontocompletethewizard.
13 of26
Figure13:ConfiguretheproductIDParametertoPullitsValuefromtheProductID QuerystringField
AftercompletingtheConfigureDataSourcewizard,VisualStudiowillcreatecorrespondingBoundFieldsanda
CheckBoxFieldintheDetailsViewfortheproductdatafields.RemovetheProductID,SupplierID,and
CategoryID BoundFieldsandconfiguretheremainingfieldsasyouseefit.Afterahandfulofaesthetic
configurations,myDetailsViewandObjectDataSourcesdeclarativemarkuplookedlikethefollowing:
<asp:DetailsViewID="ProductInfo"runat="server"AutoGenerateRows="False"
DataKeyNames="ProductID"DataSourceID="ProductDataSource"
EnableViewState="False">
<Fields>
<asp:BoundFieldDataField="ProductName"HeaderText="Product"
SortExpression="ProductName"/>
<asp:BoundFieldDataField="CategoryName"HeaderText="Category"
ReadOnly="True"SortExpression="CategoryName"/>
<asp:BoundFieldDataField="SupplierName"HeaderText="Supplier"
ReadOnly="True"SortExpression="SupplierName"/>
<asp:BoundFieldDataField="QuantityPerUnit"HeaderText="Qty/Unit"
SortExpression="QuantityPerUnit"/>
<asp:BoundFieldDataField="UnitPrice"DataFormatString="{0:c}"
HeaderText="Price"HtmlEncode="False"
SortExpression="UnitPrice"/>
<asp:BoundFieldDataField="UnitsInStock"HeaderText="UnitsInStock"
SortExpression="UnitsInStock"/>
<asp:BoundFieldDataField="UnitsOnOrder"HeaderText="UnitsOnOrder"
SortExpression="UnitsOnOrder"/>
<asp:BoundFieldDataField="ReorderLevel"HeaderText="ReorderLevel"
14 of26
SortExpression="ReorderLevel"/>
<asp:CheckBoxFieldDataField="Discontinued"HeaderText="Discontinued"
SortExpression="Discontinued"/>
</Fields>
</asp:DetailsView>
<asp:ObjectDataSourceID="ProductDataSource"runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProductByProductID"TypeName="ProductsBLL">
<SelectParameters>
<asp:QueryStringParameterName="productID"
QueryStringField="ProductID"Type="Int32"/>
</SelectParameters>
</asp:ObjectDataSource>
Totestthispage,returntoDefault.aspx andclickonViewProductsfortheBeveragescategory.Fromthe
listingofbeverageproducts,clickonthe ViewDetailslinkforChaiTea.Thiswilltakeyouto
ProductDetails.aspx?ProductID=1,whichshowsaChaiTeasdetails(seeFigure14).
Figure14:ChaiTeasSupplier,Category,Price,andOtherInformationisDisplayed
Step5:UnderstandingtheInnerWorkingsofaSiteMapProvider
ThesitemapisrepresentedinthewebserversmemoryasacollectionofSiteMapNode instancesthatforma
hierarchy.Theremustbeexactlyoneroot,allnonrootnodesmusthaveexactlyoneparentnode,andallnodes
15 of26
mayhaveanarbitrarynumberofchildren.EachSiteMapNode objectrepresentsasectioninthewebsitesstructure
thesesectionscommonlyhaveacorrespondingwebpage.Consequently,theSiteMapNode classhaspropertieslike
Title,Url,andDescription ,whichprovideinformationforthesectiontheSiteMapNode represents.Thereis
alsoaKey propertythatuniquelyidentifieseachSiteMapNode inthehierarchy,aswellaspropertiesusedto
establishthishierarchy ChildNodes,ParentNode,NextSibling,PreviousSibling,andsoforth.
Figure15showsthegeneralsitemapstructurefromFigure1,butwiththeimplementationdetailssketchedoutin
finerdetail.
Figure15:EachSiteMapNode hasPropertiesLikeTitle,Url,Key,andSoOn
additionalsitemapproviders,addthefollowingmarkuptoWeb.config:
<configuration>
<system.web>
...
<siteMapdefaultProvider="defaultProviderName">
<providers>
<addname="name"type="type"/>
</providers>
</siteMap>
</system.web>
</configuration>
Thename valueassignsahumanreadablenametotheproviderwhiletypespecifiesthefullyqualifiedtypename
ofthesitemapprovider.Wellexploreconcretevaluesforthename andtypevaluesinStep7,afterwevecreated
ourcustomsitemapprovider.
ThesitemapproviderclassisinstantiatedthefirsttimeitisaccessedfromtheSiteMap classandremainsin
memoryforthelifetimeofthewebapplication.Sincethereisonlyoneinstanceofthesitemapproviderthatmay
beinvokedfrommultiple,concurrentwebsitevisitors,itisimperativethattheprovidersmethodsbethreadsafe.
Forperformanceandscalabilityreasons,itsimportantthatwecachetheinmemorysitemapstructureandreturn
thiscachedstructureratherthanrecreatingiteverytimetheBuildSiteMap methodisinvoked.BuildSiteMap may
becalledseveraltimesperpagerequestperuser,dependingonthenavigationcontrolsinuseonthepageandthe
depthofthesitemapstructure.Inanycase,ifwedonotcachethesitemapstructureinBuildSiteMap theneach
timeitisinvokedwewouldneedtoreretrievetheproductandcategoryinformationfromthearchitecture(which
wouldresultinaquerytothedatabase).Aswediscussedinthepreviouscachingtutorials,cacheddatacanbecome
stale.Tocombatthis,wecanuseeithertimeorSQLcachedependencybasedexpiries.
Note:AsitemapprovidermayoptionallyoverridetheInitialize method.Initialize isinvokedwhen
thesitemapproviderisfirstinstantiatedandispassedanycustomattributesassignedtotheproviderin
Web.config inthe <add> elementlike:<addname="name"type="type"customAttribute="value"/>.
Itisusefulifyouwanttoallowapagedevelopertospecifyvarioussitemapproviderrelatedsettings
withouthavingtomodifytheproviderscode.Forexample,ifwewerereadingthecategoryandproducts
datadirectlyfromthedatabaseasopposedtothroughthearchitecture,wedlikelywanttoletthepage
developerspecifythedatabaseconnectionstringthroughWeb.config ratherthanusingahardcodedvaluein
theproviderscode.ThecustomsitemapproviderwellbuildinStep6doesnotoverridethisInitialize
method.ForanexampleofusingtheInitialize method,referto JeffProsisesStoringSiteMapsinSQL
Serverarticle.
Step6:CreatingtheCustomSiteMapProvider
TocreateacustomsitemapproviderthatbuildsthesitemapfromthecategoriesandproductsintheNorthwind
database,weneedtocreateaclassthatextendsStaticSiteMapProvider.InStep1Iaskedyoutoadda
CustomProviders folderintheApp_Code folder addanewclasstothisfoldernamed
NorthwindSiteMapProvider.AddthefollowingcodetotheNorthwindSiteMapProvider class:
usingSystem
usingSystem.Data
usingSystem.Configuration
usingSystem.Web
usingSystem.Web.Security
usingSystem.Web.UI
17 of26
usingSystem.Web.UI.WebControls
usingSystem.Web.UI.WebControls.WebParts
usingSystem.Web.UI.HtmlControls
usingSystem.Web.Caching
publicclassNorthwindSiteMapProvider:StaticSiteMapProvider
{
privatereadonlyobjectsiteMapLock=newobject()
privateSiteMapNoderoot=null
publicconststringCacheDependencyKey=
"NorthwindSiteMapProviderCacheDependency"
publicoverrideSiteMapNodeBuildSiteMap()
{
//Usealocktomakethismethodthreadsafe
lock(siteMapLock)
{
//First,seeifwealreadyhaveconstructedthe
//rootNode.Ifso,returnit...
if(root!=null)
returnroot
//Weneedtobuildthesitemap!
//Clearoutthecurrentsitemapstructure
base.Clear()
//Getthecategoriesandproductsinformationfromthedatabase
ProductsBLLproductsAPI=newProductsBLL()
Northwind.ProductsDataTableproducts=productsAPI.GetProducts()
//CreatetherootSiteMapNode
root=newSiteMapNode(
this,"root","~/SiteMapProvider/Default.aspx","AllCategories")
AddNode(root)
//CreateSiteMapNodesforthecategoriesandproducts
foreach(Northwind.ProductsRowproductinproducts)
{
//AddanewcategorySiteMapNode,ifneeded
stringcategoryKey,categoryName
boolcreateUrlForCategoryNode=true
if(product.IsCategoryIDNull())
{
categoryKey="Category:None"
categoryName="None"
createUrlForCategoryNode=false
}
else
{
categoryKey=string.Concat("Category:",product.CategoryID)
categoryName=product.CategoryName
}
SiteMapNodecategoryNode=FindSiteMapNodeFromKey(categoryKey)
//AddthecategorySiteMapNodeifitdoesnotexist
18 of26
if(categoryNode==null)
{
stringproductsByCategoryUrl=string.Empty
if(createUrlForCategoryNode)
productsByCategoryUrl=
"~/SiteMapProvider/ProductsByCategory.aspx?CategoryID="
+product.CategoryID
categoryNode=newSiteMapNode(
this,categoryKey,productsByCategoryUrl,categoryName)
AddNode(categoryNode,root)
}
//AddtheproductSiteMapNode
stringproductUrl=
"~/SiteMapProvider/ProductDetails.aspx?ProductID="
+product.ProductID
SiteMapNodeproductNode=newSiteMapNode(
this,string.Concat("Product:",product.ProductID),
productUrl,product.ProductName)
AddNode(productNode,categoryNode)
}
//Adda"dummy"itemtothecacheusingaSqlCacheDependency
//ontheProductsandCategoriestables
System.Web.Caching.SqlCacheDependencyproductsTableDependency=
newSystem.Web.Caching.SqlCacheDependency("NorthwindDB","Products")
System.Web.Caching.SqlCacheDependencycategoriesTableDependency=
newSystem.Web.Caching.SqlCacheDependency("NorthwindDB","Categories")
//CreateanAggregateCacheDependency
System.Web.Caching.AggregateCacheDependencyaggregateDependencies=
newSystem.Web.Caching.AggregateCacheDependency()
aggregateDependencies.Add(productsTableDependency,categoriesTableDependency)
//Addtheitemtothecachespecifyingacallbackfunction
HttpRuntime.Cache.Insert(
CacheDependencyKey,DateTime.Now,aggregateDependencies,
Cache.NoAbsoluteExpiration,Cache.NoSlidingExpiration,
CacheItemPriority.Normal,
newCacheItemRemovedCallback(OnSiteMapChanged))
//Finally,returntherootnode
returnroot
}
}
protectedoverrideSiteMapNodeGetRootNodeCore()
{
returnBuildSiteMap()
}
protectedvoidOnSiteMapChanged(stringkey,objectvalue,CacheItemRemovedReasonreason)
{
lock(siteMapLock)
{
19 of26
if(string.Compare(key,CacheDependencyKey)==0)
{
//Refreshthesitemap
root=null
}
}
}
publicDateTime?CachedDate
{
get
{
returnHttpRuntime.Cache[CacheDependencyKey]asDateTime?
}
}
}
Areferencetothesitemapprovider(this).
TheSiteMapNodesKey.ThisrequiredvaluemustbeuniqueforeachSiteMapNode.
TheSiteMapNodesUrl.Url isoptional,butifprovided,eachSiteMapNodesUrl valuemustbeunique.
TheSiteMapNodesTitle,whichisrequired.
Step7:RegisteringtheNorthwindSiteMapProvider
InorderforourwebapplicationtousetheNorthwindSiteMapProvider sitemapprovidercreatedinStep6,we
needtoregisteritinthe<siteMap> sectionofWeb.config.Specifically,addthefollowingmarkupwithinthe
<system.web> elementinWeb.config :
<siteMapdefaultProvider="AspNetXmlSiteMapProvider">
<providers>
<addname="Northwind"type="NorthwindSiteMapProvider"/>
</providers>
</siteMap>
21 of26
navigationinterfaceontheleftstillshowsthesectionsandtutorialsdefinedinWeb.sitemap.Thisisbecausewe
leftAspNetXmlSiteMapProvider asthedefaultprovider.Inordertocreateanavigationuserinterfaceelementthat
usestheNorthwindSiteMapProvider,wellneedtoexplicitlyspecifythattheNorthwindsitemapprovider
shouldbeused.WellseehowtoaccomplishthisinStep8.
Step8:DisplayingSiteMapInformationUsingtheCustomSiteMap
Provider
WiththecustomsitemapprovidercreatedandregisteredinWeb.config,werereadytoaddnavigationcontrolsto
theDefault.aspx,ProductsByCategory.aspx,andProductDetails.aspx pagesintheSiteMapProvider
folder.StartbyopeningtheDefault.aspx pageanddragaSiteMapPath fromtheToolboxontotheDesigner.The
SiteMapPathcontrolislocatedintheNavigationsectionoftheToolbox.
Figure16:AddaSiteMapPathtoDefault.aspx
TheSiteMapPathcontroldisplaysabreadcrumb,indicatingthecurrentpageslocationwithinthesitemap.We
addedaSiteMapPathtothetopofthemasterpagebackintheMasterPagesandSiteNavigation tutorial.
Takeamomenttoviewthispagethroughabrowser.TheSiteMapPathaddedinFigure16usesthedefaultsitemap
provider,pullingitsdatafromWeb.sitemap.Therefore,thebreadcrumbshowsHome>CustomizingtheSite
Map, justlikethebreadcrumbintheupperrightcorner.
22 of26
Figure17:TheBreadcrumbUsestheDefaultSiteMapProvider
TohavetheSiteMapPathaddedinFigure16usethecustomsitemapproviderwecreatedinStep6,setits
SiteMapProvider propertytoNorthwind, thenameweassignedtotheNorthwindSiteMapProvider in
Web.config.Unfortunately,theDesignercontinuestousethedefaultsitemapprovider,butifyouvisitthepage
throughabrowseraftermakingthispropertychangeyoullseethatthebreadcrumbnowusesthecustomsitemap
provider.
Figure18:TheBreadcrumbNowUsestheCustomSiteMapProviderNorthwindSiteMapProvider
TheSiteMapPathcontroldisplaysamorefunctionaluserinterfaceintheProductsByCategory.aspx and
23 of26
DetailslinkforChaiTea.AsFigure19shows,thebreadcrumbincludesthecurrentsitemapsection(ChaiTea)
anditsancestors:Beveragesand AllCategories.
Figure19:TheBreadcrumbNowUsestheCustomSiteMapProviderNorthwindSiteMapProvider
OthernavigationuserinterfaceelementscanbeusedinadditiontotheSiteMapPath,suchastheMenuand
TreeViewcontrols.TheDefault.aspx,ProductsByCategory.aspx,andProductDetails.aspx pagesinthe
downloadforthistutorial,forexample,allincludeMenucontrols(seeFigure20).SeeExaminingASP.NET2.0s
SiteNavigationFeaturesandtheUsingSiteNavigationControlssectionoftheASP.NET2.0QuickStartsfora
moreindepthlookatthenavigationcontrolsandsitemapsysteminASP.NET2.0.
24 of26
Figure20:TheMenuControlListsEachoftheCategoriesandProducts
Asmentionedearlierinthistutorial,thesitemapstructurecanbeaccessedprogrammaticallythroughtheSiteMap
class.ThefollowingcodereturnstherootSiteMapNode ofthedefaultprovider:
SiteMapNoderoot=SiteMap.RootNode
SincetheAspNetXmlSiteMapProvider isthedefaultproviderforourapplication,theabovecodewouldreturnthe
rootnodedefinedinWeb.sitemap.Toreferenceasitemapproviderotherthanthedefault,usetheSiteMap classs
Providers propertylikeso:
SiteMapNoderoot=SiteMap.Providers["name"].RootNode
Note:BesuretotestouttheSQLcachedependencyfeature.AftervisitingtheDefault.aspx,
25 of26
ProductsByCategory.aspx,andProductDetails.aspx pages,gotooneofthetutorialsintheEditing,
Inserting,andDeletingsectionandeditthenameofacategoryorproduct.Thenreturntooneofthepagesin
theSiteMapProvider folder.Assumingenoughtimehaspassedforthepollingmechanismtonotethe
changetotheunderlyingdatabase,thesitemapshouldbeupdatedtoshowthenewproductorcategory
name.
Summary
ASP.NET2.0ssitemapfeaturesincludesaSiteMap class,anumberofbuiltinnavigationWebcontrols,anda
defaultsitemapproviderthatexpectsthesitemapinformationpersistedtoanXMLfile.Inordertousesitemap
informationfromsomeothersourcesuchasfromadatabase,theapplicationsarchitecture,oraremoteWeb
service weneedtocreateacustomsitemapprovider.Thisinvolvescreatingaclassthatderives,directlyor
indirectly,fromtheSiteMapProvider class.
Inthistutorialwesawhowtocreateacustomsitemapproviderthatbasedthesitemapontheproductand
categoryinformationculledfromtheapplicationarchitecture.OurproviderextendedtheStaticSiteMapProvider
classandentailedcreatingaBuildSiteMap methodthatretrievedthedata,constructedthesitemaphierarchy,and
cachedtheresultingstructureinaclasslevelvariable.WeusedaSQLcachedependencywithacallbackfunction
toinvalidatethecachedstructurewhentheunderlyingCategories orProducts dataismodified.
HappyProgramming!
FurtherReading
Formoreinformationonthetopicsdiscussedinthistutorial,refertothefollowingresources:
l
l
l
l
StoringSiteMapsinSQLServer andTheSQLSiteMapProviderYouveBeenWaitingFor
ALookatASP.NET2.0sProviderModel
TheProviderToolkit
ExaminingASP.NET2.0sSiteNavigationFeatures
AbouttheAuthor
ScottMitchell,authorofsevenASP/ASP.NETbooksandfounderof4GuysFromRolla.com,hasbeenworkingwith
MicrosoftWebtechnologiessince1998.Scottworksasanindependentconsultant,trainer,andwriter.Hislatest
bookisSamsTeachYourselfASP.NET2.0in24Hours.Hecanbereachedatmitchell@4GuysFromRolla.com. or
viahisblog,whichcanbefoundat http://ScottOnWriting.NET.
SpecialThanksTo
Thistutorialserieswasreviewedbymanyhelpfulreviewers.LeadreviewersforthistutorialwereDaveGardner,
ZackJones,TeresaMurphy,andBernadetteLeigh.InterestedinreviewingmyupcomingMSDNarticles?Ifso,
dropmealineat mitchell@4GuysFromRolla.com.
26 of26