MvcSiteMapProvider ISiteMapBuilder в сочетании с IDynamicNodeProvider
Я использую MvcSiteMapProvider 4.4.3 для динамического создания карты сайта из базы данных. Я следую за этой статьей: https://github.com/maartenba/MvcSiteMapProvider/wiki/Multiple-Sitemaps-in-One-Application потому что я использую несколько файлов Sitemap.
Это работает, и это основная структура, которая возвращается:
- Главная
- Новости
- Товары
- Около
- контакт
Один из узлов (/Products
) должен быть динамически заполнен снова на основе разных данных. Так что для этого мне нужен IDynamicNodeProvider
реализация на /Products
узел? (пожалуйста, поправьте меня, если я ошибаюсь?)
Во всяком случае, я думаю, что мне нужно выше. Документация показывает способы сделать это на узле, определенном в XML, и на узле, определенном с использованием атрибутов действий контроллера, но не "вручную" в ISiteMapBuilder
, Так что, если я установлю .DynamicNodeProvider
собственность ISiteMapNode
Экземпляр, кажется, не создается... .HasDynamicNodeProvider
свойство также возвращает false
,
Глядя на источник, я вижу PluginProvider
-материал, который связан с DynamicNodeProviderStrategy
и вот, они потеряли меня...
Как мне создать ISiteMapNode
за " /Products
" в моем ISiteMapBuilder
так что это потомки ( /Products/Cat
а также /Products/Cat/Product
) динамически загружаются из базы данных?
1 ответ
Вы можете сделать это с ISiteMapBuilder, но вам, вероятно, лучше вместо реализации ISiteMapNodeProvider. Причина в том, что добавление узлов в SiteMap должно выполняться в самом конце процесса после того, как все узлы были созданы, чтобы гарантировать, что каждый узел правильно сопоставлен с родительским узлом (за исключением, конечно, корневого узла, который не нужен родитель). Это было главное изменение дизайна, которое было сделано в 4.3.0.
Класс SiteMapBuilder по умолчанию уже настроен для обеспечения
- Узлы правильно сопоставлены с их родительскими узлами
- Существует только 1 корневой узел
- Все узлы добавляются в SiteMap
- Посетители выполняются последними после того, как SiteMap полностью построен
Не имеет смысла добавлять более одного экземпляра ISiteMapBuilder, потому что это позволяет обойти эту важную логику. Поэтому лучше, если вы не реализуете ISiteMapBuilder, а вместо этого реализуете ISiteMapNodeProvider.
Класс SiteMapBuilder принимает ISiteMapNodeProvider в качестве зависимости через своего конструктора. Вы можете использовать класс CompositeSiteMapNodeProvider для обработки множественности в этом интерфейсе, так что вы можете добавить более одной реализации ISiteMapNodeProvider, если это необходимо.
Интерфейс ISiteMapNodeProvider выглядит следующим образом:
public interface ISiteMapNodeProvider
{
IEnumerable<ISiteMapNodeToParentRelation> GetSiteMapNodes(ISiteMapNodeHelper helper);
}
Существует всего 1 способ для реализации. Кроме того, многие обычные (но необязательные) сервисы внедряются через интерфейс автоматически из класса SiteMapBuilder через ISiteMapNodeHelper.
Этот класс находится на более низком уровне, чем IDynamicNodeProvider. Вы взаимодействуете с ISiteMapNode напрямую, но все взаимодействие с классом SiteMap обрабатывается SiteMapBuilder. ISiteMapNode обернут в экземпляр ISiteMapNodeToParentRelation, который только для того, чтобы гарантировать, что его ключ родительского узла может отслеживаться до момента его добавления в объект SiteMap.
Ваш SiteMapNodeProvider должен выглядеть примерно так:
public class CustomSiteMapNodeProvider
: ISiteMapNodeProvider
{
private readonly string sourceName = "CustomSiteMapNodeProvider";
#region ISiteMapNodeProvider Members
public IEnumerable<ISiteMapNodeToParentRelation> GetSiteMapNodes(ISiteMapNodeHelper helper)
{
var result = new List<ISiteMapNodeToParentRelation>();
using (var db = new DatabaseContextClass())
{
foreach (var category in db.Categories.ToList())
{
var categoryRelation = this.GetCategoryRelation("Products", category, helper);
result.Add(categoryRelation);
}
foreach (var product in db.Products.Include("Category"))
{
var productRelation = this.GetProductRelation("Category_" + product.CategoryId, product, helper);
result.Add(productRelation);
}
}
return result;
}
#endregion
protected virtual ISiteMapNodeToParentRelation GetCategoryRelation(string parentKey, Category category, ISiteMapNodeHelper helper)
{
string key = "Category_" + category.Id;
var result = helper.CreateNode(key, parentKey, this.sourceName);
var node = result.Node;
node.Title = category.Name;
// Populate other node properties here
// Important - always set up your routes (including any custom params)
node.Area = "MyArea"; // Required - set to empty string if not using areas
node.Controller = "Category"; // Required
node.Action = "Index"; // Required
node.RouteValues.Add("id", category.Id.ToString());
return result;
}
protected virtual ISiteMapNodeToParentRelation GetProductRelation(string parentKey, Product product, ISiteMapNodeHelper helper)
{
string key = "Product_" + product.Id;
var result = helper.CreateNode(key, parentKey, this.sourceName);
var node = result.Node;
node.Title = product.Name;
// Populate other node properties here
// Important - always set up your routes (including any custom params)
node.Area = "MyArea"; // Required - set to empty string if not using areas
node.Controller = "Product"; // Required
node.Action = "Index"; // Required
node.RouteValues.Add("id", product.Id.ToString());
node.RouteValues.Add("categoryId", product.CategoryId.ToString()); // Optional - use if you have a many-to-many relationship.
return result;
}
}
В приведенном выше примере предполагается, что вы добавили узел другим способом, для которого установлен ключ "Продукты", дочерними элементами которого будут все категории. Конечно, вы можете настроить это в соответствии с вашими потребностями.
Обычно лучше, если вы реализуете этот интерфейс только один раз и используете одно соединение с базой данных для загрузки всего SiteMap. Вы всегда можете реорганизовать это в несколько классов, каждый из которых обрабатывает одну таблицу на вашей стороне интерфейса, чтобы разделить проблемы. Но, как правило, лучше всего объединить всю логику сопоставления клавиш между связанными объектами, чтобы упростить поддержку.
Дополнительные примеры реализации этого интерфейса см. В разделах XmlSiteMapNodeProvider и ReflectionSiteMapNodeProvider.