1

我正在使用 MvcSiteMapProvider 4.4.3 从数据库中动态构建站点地图。我正在关注这篇文章:https ://github.com/maartenba/MvcSiteMapProvider/wiki/Multiple-Sitemaps-in-One-Application ,因为我正在使用多个站点地图。

这有效,这是返回的基本结构:

    • 消息
    • 产品
    • 关于
    • 接触

/Products应根据不同的数据再次动态填充节点之一 ( )。所以为此我需要IDynamicNodeProvider/Products节点上实现?(如果我错了请纠正我?

无论如何,我想我确实需要上述内容。文档显示了在 XML 中定义的节点和使用控制器操作上的属性定义的节点上执行此操作的方法,但不是在ISiteMapBuilder. 因此,如果我设置实例的.DynamicNodeProvider属性,ISiteMapNode它似乎没有被实例化......该.HasDynamicNodeProvider属性也返回false

查看源代码,我看到PluginProvider了相关的东西,DynamicNodeProviderStrategy然后你去了,他们失去了我......

如何在我的中创建一个ISiteMapNodefor " /Products"ISiteMapBuilder以便它的后代 (/Products/Cat/Products/Cat/Product) 是从数据库中动态加载的?

4

1 回答 1

3

您可以使用 ISiteMapBuilder 执行此操作,但您最好还是实现 ISiteMapNodeProvider。原因是因为必须在所有节点都被实例化后,在流程的最后阶段将节点添加到 SiteMap,以确保每个节点都正确映射到父节点(当然,根节点除外,它没有需要父母)。这是在 4.3.0 中完成的主要设计更改。

现在已经设置了默认的 SiteMapBuilder 类以确保

  1. 节点正确映射到它们的父节点
  2. 只有1个根节点
  3. 所有节点都添加到 SiteMap
  4. 访问者在站点地图完全构建后最后执行

添加多个 ISiteMapBuilder 实例是没有意义的,因为这样可以规避这一重要逻辑。因此,最好不实现 ISiteMapBuilder,而是实现 ISiteMapNodeProvider。

SiteMapBuilder 类通过其构造函数将 ISiteMapNodeProvider 作为依赖项。您可以使用 CompositeSiteMapNodeProvider 类来处理此接口上的多重性,因此您可以在需要时添加多个 ISiteMapNodeProvider 实现。

ISiteMapNodeProvider 接口如下所示:

public interface ISiteMapNodeProvider
{
    IEnumerable<ISiteMapNodeToParentRelation> GetSiteMapNodes(ISiteMapNodeHelper helper);
}

只有一种方法可以实现。此外,许多常见(但可选)服务是通过 ISiteMapNodeHelper 从 SiteMapBuilder 类通过接口自动注入的。

该类的级别低于 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;
    }
}

上面的示例假设您已通过其他方式添加了一个节点,该节点的键设置为“Products”,所有类别都将是该节点的子级。您当然可以调整它以满足您的需求。

通常最好只实现此接口 1 次并使用单个数据库连接来加载整个 SiteMap。您始终可以将其重构为多个类,每个类处理您界面一侧的单个表以分离关注点。但通常最好将相关实体之间的所有键映射逻辑放在一起以使其更易于维护。

有关此接口实现的其他示例,请参阅XmlSiteMapNodeProviderReflectionSiteMapNodeProvider

于 2013-10-01T15:51:24.030 回答