📜 ⬆️ ⬇️

Practical use of MvcSiteMapProvider in ASP.net MVC

Practical use of MvcSiteMapProvider in ASP.net MVC

This article shows how to use MvcSiteMapProvider to build a dynamic menu, how to make a sitemap and “breadcrumbs” with it.

I will show the practice of using MvcSiteMapProvider on the MVC Music Store training project.

Site structure is as follows
Home
Store
Rock
The Best Of Men At Work The Best Of Men At Work
For Those About
Classical
Jazz
...
Admin
')
MvcSiteMapProvider sources are on Github , MS-PL License.
Installing into a project using nuget (View-> Other windows-> Package Manager Console)
 PM> Install-Package MvcSiteMapProvider

After installing this package, a new view will appear in the Views / Shared / DisplayTemplates folder.

I deleted unnecessary * .ascx files.
Also Mvc.sitemap and MvcSiteMapSchema.xsd will appear in the project root.
The following lines will be added to the web.config:
<siteMap defaultProvider="MvcSiteMapProvider" enabled="true"> <providers> <clear /> <add name="MvcSiteMapProvider" type="MvcSiteMapProvider.DefaultSiteMapProvider, MvcSiteMapProvider" siteMapFile="~/Mvc.Sitemap" securityTrimmingEnabled="true" cacheDuration="5" enableLocalization="true" scanAssembliesForSiteMapNodes="true" includeAssembliesForScan="" excludeAssembliesForScan="" attributesToIgnore="visibility" nodeKeyGenerator="MvcSiteMapProvider.DefaultNodeKeyGenerator, MvcSiteMapProvider" controllerTypeResolver="MvcSiteMapProvider.DefaultControllerTypeResolver, MvcSiteMapProvider" actionMethodParameterResolver="MvcSiteMapProvider.DefaultActionMethodParameterResolver, MvcSiteMapProvider" aclModule="MvcSiteMapProvider.DefaultAclModule, MvcSiteMapProvider" siteMapNodeUrlResolver="MvcSiteMapProvider.DefaultSiteMapNodeUrlResolver, MvcSiteMapProvider" siteMapNodeVisibilityProvider="MvcSiteMapProvider.DefaultSiteMapNodeVisibilityProvider, MvcSiteMapProvider" siteMapProviderEventHandler="MvcSiteMapProvider.DefaultSiteMapProviderEventHandler, MvcSiteMapProvider" /> </providers> </siteMap> </code> 

To begin with, we are interested in Mvc.sitemap, by default it looks like:
 <?xml version="1.0" encoding="utf-8" ?> <mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0" xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0 MvcSiteMapSchema.xsd" enableLocalization="true"> <mvcSiteMapNode title="Home" controller="Home" action="Index"> <mvcSiteMapNode title="About" controller="Home" action="About"/> </mvcSiteMapNode> </mvcSiteMap> 

The mvcSiteMapNode Xml element is the main element of the site map. Its main attributes are:

I added nodes to it corresponding to the site structure:
 <?xml version="1.0" encoding="utf-8" ?> <mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0" xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0 MvcSiteMapSchema.xsd" enableLocalization="true"> <mvcSiteMapNode title="Home" controller="Home" action="Index"> <mvcSiteMapNode title="Store" controller="Store" action="Index"> </mvcSiteMapNode> <mvcSiteMapNode title="Cart" controller="ShoppingCart" action="Index" /> <mvcSiteMapNode title="Admin" controller="StoreManager" action="Index" > </mvcSiteMapNode> </mvcSiteMapNode> </mvcSiteMap> 


Only 4 main pages are added here. Now you need to add genres and albums to the site map:

Since we have a dynamic site, then albums and genres will constantly change and a static sitemap will not work. To solve this problem, MvcSiteMapProvider has a dynamicNodeProvider. So, create a class inherited from DynamicNodeProviderBase and override the GetDynamicNodeCollection method, the data will be taken from the database:

 public class StoreDynamicNodeProvider : DynamicNodeProviderBase { public MusicStoreEntities _db = new MusicStoreEntities(); public override IEnumerable<DynamicNode> GetDynamicNodeCollection() { var nodes = new List<DynamicNode>(); var items = _db.Genres.ToList(); foreach (var item in items) { DynamicNode node = new DynamicNode(); //        node.Key = "store_" + item.GenreId.ToString(); node.RouteValues.Add("genre", item.Name); node.Action = "Browse"; node.Controller = "Store"; node.Title = item.Name; nodes.Add(node); if (item.Albums!=null) { foreach (var item2 in item.Albums) { DynamicNode node2 = new DynamicNode(); node2.Key = "album_" + item2.AlbumId.ToString(); node2.ParentKey = node.Key; node2.RouteValues.Add("id", item2.AlbumId); node2.Action = "Details"; node2.Controller = "Store"; node2.Title = item2.Title; nodes.Add(node2); } } } return nodes; } } 


Now you need to change Store's node in Mvc.sitemap:
 <mvcSiteMapNode title="Store" controller="Store" action="Index"> <mvcSiteMapNode title="" controller="Store" action="Index" dynamicNodeProvider="MvcMusicStore.Infrastructure.StoreDynamicNodeProvider, MvcMusicStore"/> </mvcSiteMapNode> 


Here the main change is the addition of the dynamicNodeProvider attribute, which specifies the full path to the class-generator of dynamic nodes.

Add breadcrumbs to the site template and menu drawing
Add to the Views / Shared / _Layout.cshtml file:
  <div style="text-align: center;">  : @Html.MvcSiteMap().SiteMapPath() </div> @Html.MvcSiteMap().Menu(2, 1) 


Now make a selection of the active item in the left menu, for this you need to change the template Views / Shared / DisplayTemplates / MenuHelperModel.cshtml
 <ul id="menu"> @foreach (var node in Model.Nodes) { <li style="@(node.IsInCurrentPath && !node.IsRootNode ? "text-decoration: underline;" : "")"> <a href="@node.Url">@node.Title</a> </li> } </ul> 

It turns out about the following:


Go to the admin.
In the admin panel, I want only the path on the site to be displayed, but the menu on the left is not.
The structure is as follows:


Similarly for the Store section, let's add a class inherited from DynamicNodeProviderBase.

 public class AdminDynamicNodeProvider : DynamicNodeProviderBase { public MusicStoreEntities _db = new MusicStoreEntities(); public override IEnumerable<DynamicNode> GetDynamicNodeCollection() { var nodes = new List<DynamicNode>(); var items = _db.Albums.ToList(); foreach (var item in items) { var node=new DynamicNode() { Key="admin_album_edit_"+ item.AlbumId.ToString(), Action="Edit", Controller="StoreManager", Title="  "+item.Title }; node.RouteValues.Add("id", item.AlbumId); nodes.Add(node); node = new DynamicNode() { Key = "admin_album_delete_" + item.AlbumId.ToString(), Action = "Delete", Controller = "StoreManager", Title = "  " + item.Title }; node.RouteValues.Add("id", item.AlbumId); nodes.Add(node); node = new DynamicNode() { Key = "admin_album_details_" + item.AlbumId.ToString(), Action = "Details", Controller = "StoreManager", Title = "  " + item.Title }; node.RouteValues.Add("id", item.AlbumId); nodes.Add(node); } return nodes; } } 


Similarly, change the Admin node:
 <mvcSiteMapNode title="Admin" controller="StoreManager" action="Index" > <mvcSiteMapNode title="" controller="StoreManager" action="Index" dynamicNodeProvider="MvcMusicStore.Infrastructure.AdminDynamicNodeProvider, MvcMusicStore"/> <mvcSiteMapNode title="Create" controller="StoreManager" action="Create" /> </mvcSiteMapNode> 


The following will turn out:


We need to hide all unnecessary items in the menu, but the path on the site should be displayed correctly. To do this, add the visibility = "SiteMapPathHelper,! *" Attribute to the required nodes in Mvc.sitemap, and then use thezept in its math service in the section where Mvc.sitemap is added to change the value of the siteMapNodeVisibilityProvider attribute to "MvcSiteMapProvider.FilteredSiteMapNefePToider" to set the value of the siteMapPathHelper .
The final version of the Mvc.sitemap file:
 <?xml version="1.0" encoding="utf-8" ?> <mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0" xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0 MvcSiteMapSchema.xsd" enableLocalization="true"> <mvcSiteMapNode title="Home" controller="Home" action="Index" visibility=""> <mvcSiteMapNode title="Store" controller="Store" action="Index"> <mvcSiteMapNode title="" controller="Store" action="Index" dynamicNodeProvider="MvcMusicStore.Infrastructure.StoreDynamicNodeProvider, MvcMusicStore"/> </mvcSiteMapNode> <mvcSiteMapNode title="Cart" controller="ShoppingCart" action="Index" /> <mvcSiteMapNode title="Admin" controller="StoreManager" action="Index" > <mvcSiteMapNode title="" controller="StoreManager" action="Index" visibility="SiteMapPathHelper,!*" dynamicNodeProvider="MvcMusicStore.Infrastructure.AdminDynamicNodeProvider, MvcMusicStore"/> <mvcSiteMapNode title="Create" controller="StoreManager" visibility="SiteMapPathHelper,!*" action="Create" /> </mvcSiteMapNode> </mvcSiteMapNode> </mvcSiteMap> 


Now everything is displayed correctly:


That's all.
Sample source codes can be downloaded here.

Source: https://habr.com/ru/post/175431/


All Articles