- PVSM.RU - https://www.pvsm.ru -
Практическое использование MvcSiteMapProvider в ASP.net MVC
В данной статье показано использование MvcSiteMapProvider для построения динамического меню, как с его помощью сделать карту сайта и «breadcrumbs».
Практику использвания MvcSiteMapProvider я буду показывать на учебном проекте MVC Music Store [1].
Структура сайта следующая
Home
Store
Rock
The Best Of Men At Work The Best Of Men At Work
For Those About To Rock We Salute You
Classical
Jazz
…
Admin
Исходники MvcSiteMapProvider лежат на Github [2], лицензия MS-PL License.
Установка в проект с помощью nuget (Вид->Другие окна->Консоль диспетчера пакетов)
PM>Install-Package MvcSiteMapProvider
После установки этого пакета в папке Views/Shared/DisplayTemplates появятся новые view.
Не нужные *.ascx файлы я удалил.
Также в корне проекта появятся Mvc.sitemap и MvcSiteMapSchema.xsd.
В 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>
Для начала нас интересует Mvc.sitemap, по умолчанию он имеет вид:
<?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>
Xml-элемент mvcSiteMapNode — основной элемент карты сайта. Его основные атрибуты:
Я добавил в него ноды соответствующие структуре сайта:
<?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>
Здесь добавлены только 4 основных страницы. Теперь необходимо добавить жанры и альбомы в карту сайта:
Т.к. сайт у нас динамический, то альбомы и жанры будут постоянно меняться и статичная карта сайта не подойдёт. Для решения этой проблемы в MvcSiteMapProvider есть dynamicNodeProvider. Итак, создадим класс унаследованный от DynamicNodeProviderBase и переопределим метод GetDynamicNodeCollection, данные будут браться из бд:
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;
}
}
Теперь необходимо в Mvc.sitemap поменять ноду Store:
<mvcSiteMapNode title="Store" controller="Store" action="Index">
<mvcSiteMapNode title="" controller="Store" action="Index" dynamicNodeProvider="MvcMusicStore.Infrastructure.StoreDynamicNodeProvider, MvcMusicStore"/>
</mvcSiteMapNode>
Здесь главное изменение — добавление атрибута dynamicNodeProvider, в котором указывается полный путь к классу-генератору динамических нод.
Добавим breadcrumbs в шаблон сайта и отрисовку меню
В файл Views/Shared/_Layout.cshtml добавим:
<div style="text-align: center;">
Вы здесь: @Html.MvcSiteMap().SiteMapPath()
</div>
@Html.MvcSiteMap().Menu(2, 1)
Теперь сделаем выделение активного пункта в левом меню, для этого надо изменить шаблон 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>
Получится примерно следующее:
Переходим к админке.
В админке я хочу, чтобы отображался только путь на сайте, а меню слева — нет.
Структура следующая:
Аналогично для раздела Store, добавим класс унаследованный от 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;
}
}
Аналогично изменим ноду Admin:
<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>
Получится следующее:
Нам необходимо скрыть в меню все ненужные пункты, но путь на сайте должен отображаться корректно. Для этого в Mvc.sitemap в необходимых нодах добавляем атрибут visibility=«SiteMapPathHelper,!*», а чтобы он заработал важно в web.config в разделе где добавляется Mvc.sitemap поменять значение атрибута siteMapNodeVisibilityProvider на «MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider».
Окончательная версия файла Mvc.sitemap:
<?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>
Теперь всё отображается корректно:
Вот, собственно, и всё.
Исходные коды примера можно скачать здесь [3]
Автор: slrzz
Источник [4]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/asp-net-mvc/33274
Ссылки в тексте:
[1] MVC Music Store: http://mvcmusicstore.codeplex.com/
[2] Github: https://github.com/maartenba/MvcSiteMapProvider
[3] здесь: http://slrz.ru/MvcMusicStore-w-SiteMap.zip
[4] Источник: http://habrahabr.ru/post/175431/
Нажмите здесь для печати.