首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在MvcSiteMapProvider中为具有动态参数的DynamicNode创建子节点

在MvcSiteMapProvider中为具有动态参数的DynamicNode创建子节点
EN

Stack Overflow用户
提问于 2010-11-10 03:51:45
回答 1查看 10K关注 0票数 19

我使用的是MvcSiteMapProvider 2.2.1 (http://mvcsitemap.codeplex.com),在动态节点(使用dynamicNodeProvider)下创建具有动态参数(id)的子节点时遇到问题。

我正在失去以下路线的面包屑:

Stores/5/Products/Edit/23

其中,url模式为:

Stores/{storeID}/{controller}/{action}/{id}

当ID被省略(即"New“操作)时,它工作得很好。但是当指定ID时,它与路由不匹配,并且我的面包屑(使用SiteMapPath帮助器)为空。

My Sitemap: (缩写)

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-2.0">
    <mvcSiteMapNode title="Home" controller="Dashboard" action="Index" changeFrequency="Always" updatePriority="Normal">
        <mvcSiteMapNode title="My Account" controller="Account" action="Index" key="Account" />
        <mvcSiteMapNode title="My Stores" area="Stores" controller="Home" action="Index" visibilityProvider="ControlPanel.Areas.Stores.StoreAreaVisibilityProvider, ControlPanel"  >
            <mvcSiteMapNode title="Store" action="Index" dynamicNodeProvider="ControlPanel.Areas.Stores.StoreAreaNodeProvider, ControlPanel" />
        </mvcSiteMapNode>
    </mvcSiteMapNode>
</mvcSiteMap>

区域注册:

代码语言:javascript
复制
public override void RegisterArea(AreaRegistrationContext context)
{
        context.MapRoute(
            "Store_Index",
            "Stores",
            new { action = "Index", controller = "Home" },
            new string[] { "ControlPanel.Areas.Stores.Controllers" }
            );

        context.MapRoute(
            "Store_default",
            "Stores/{storeID}/{controller}/{action}/{id}",
            new { action = "Index", controller = "Manage", id = UrlParameter.Optional },
            new { storeID = @"\d+" },
            new string[] { "ControlPanel.Areas.Stores.Controllers" }
        );
    }

第一次尝试:

我尝试的第一件事就是在sitemap xml中创建子节点作为动态节点的子节点。这根本不起作用,这些人最终成为了"Home“的孩子。我会在其中放一个ParentKey属性,除非每个商店都会重复这些属性,因此会有多个父键

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-2.0">
  <mvcSiteMapNode title="Home" controller="Dashboard" action="Index" changeFrequency="Always" updatePriority="Normal">
    <mvcSiteMapNode title="My Account" controller="Account" action="Index" key="Account" />
    <mvcSiteMapNode title="My Stores" area="Stores" controller="Home" action="Index" visibilityProvider="ControlPanel.Areas.Stores.StoreAreaVisibilityProvider, ControlPanel"  >
      <mvcSiteMapNode title="Store" action="Index" dynamicNodeProvider="ControlPanel.Areas.Stores.StoreAreaNodeProvider, ControlPanel">
        <mvcSiteMapNode title="Products" area="Stores" controller="Products" action="Index">
          <mvcSiteMapNode title="Edit" area="Stores" controller="Products" action="Edit"/>
          <mvcSiteMapNode title="New" area="Stores" controller="Products" action="Edit"/>
        </mvcSiteMapNode>
      </mvcSiteMapNode>
    </mvcSiteMapNode>
  </mvcSiteMapNode>
</mvcSiteMap>

第二次尝试:

似乎下一个选择就是直接在我的DynamicNodeProvider中添加子节点。除了具有动态参数的节点之外,这种方法的效果要好得多

(为便于解释,对以下内容进行了修改...)

代码语言:javascript
复制
public class StoreAreaNodeProvider : IDynamicNodeProvider
{
    public IEnumerable<DynamicNode> GetDynamicNodeCollection()
    {
        var nodes = new List<DynamicNode>();

        foreach (var store in repo.GetStores())
        {
            DynamicNode node = new DynamicNode();
            node.Title = store.Name;
            node.Area = "Stores";
            node.Controller = "Manage";
            node.Action = "Index";
            node.RouteValues.Add("storeID", store.StoreID);
            node.Key = "Store_" + store.StoreID.ToString();

            nodes.Add(node);

            //Child of node
            DynamicNode productsNode = new DynamicNode();
            productsNode.Title = "Products";
            productsNode.Area = "Stores";
            productsNode.Controller = "Products";
            productsNode.Action = "Index";
            productsNode.RouteValues.Add("storeID", store.StoreID);
            productsNode.ParentKey = String.Format("Store_{0}", store.StoreID.ToString());
            productsNode.Key = String.Format("Store_{0}_Products", store.StoreID.ToString());

            nodes.Add(productsNode);

            //child of productsNode
            DynamicNode editNode = new DynamicNode();
            editNode.Title = "Edit";
            editNode.Area = "Stores";
            editNode.Action = "Edit";
            editNode.Controller = "Products";
            editNode.RouteValues.Add("storeID", store.StoreID);
            //I can't add the RouteValue "ID" here because it is dynamic
            //I would have do loop through every product for this store with
            //another dynamic node provider, but that seems terribly inefficient and stupid
            editNode.ParentKey = String.Format("Store_{0}_Products", store.StoreID.ToString());
            editNode.Attributes.Add("visibility", "SiteMapPathHelper,!*");

            nodes.Add(editNode);
        }

        return nodes;
    }
}

摘要中的

有效:Store/5/Products/New

不起作用:Store/5/Products/Edit/23

对于Url模式:Store/{storeID}/{控制器}/{操作}/{id}

我希望能够做的事情:

代码语言:javascript
复制
editNode.Attributes.Add("isDynamic", "true");
editNode.Attributes.Add("dynamicParameters", "id");

如何在dynamicNode的子节点上模拟旧的MvcSiteMapProvider的dynamicParameters属性?基本上,我需要它在匹配路由时忽略"id“路由值。

希望我正确地解释了这一点,并且没有向您提供大量信息。谢谢!

更新:

以下是基于Jakub的答案对我起作用的解决方案。

在MvcSiteMapProvider 2.x中,您可以创建自己的ISiteMapNodeUrlResolver实现,而不必修改源代码。因此,我基本上添加了具有dynamicParameters属性的功能

类:

代码语言:javascript
复制
namespace ControlPanel
{
    public class CustomSiteMapNodeUrlResolver : ISiteMapNodeUrlResolver
    {
        public virtual string ResolveUrl(MvcSiteMapNode mvcSiteMapNode, string area, string controller, string action, IDictionary<string, object> routeValues)
        {
            RequestContext ctx;
            if (HttpContext.Current.Handler is MvcHandler)
                ctx = ((MvcHandler)HttpContext.Current.Handler).RequestContext;
            else
                ctx = new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData());

            //Begin Added Code
            if (mvcSiteMapNode["dynamicParameters"] != null)
            {
                foreach (var item in mvcSiteMapNode["dynamicParameters"].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    var dp = item.Trim();
                    routeValues[da] = ctx.RouteData.Values[dp];
                }
            }
            //End Added Code

            return new UrlHelper(ctx).Action(action, controller, new RouteValueDictionary(routeValues));
        }
    }
}

Web.config:

代码语言:javascript
复制
<siteMap defaultProvider="MvcSiteMapProvider" enabled="true">
  <providers>
    <clear/>
    <add name="MvcSiteMapProvider"
         type="MvcSiteMapProvider.DefaultSiteMapProvider, MvcSiteMapProvider"
         siteMapFile="~/Mvc.Sitemap"
         securityTrimmingEnabled="true"
         attributesToIgnore="visibility,dynamicParameters"
         scanAssembliesForSiteMapNodes="true" 
         siteMapNodeUrlResolver="ControlPanel.CustomSiteMapNodeUrlResolver, ControlPanel"
         siteMapNodeVisibilityProvider="MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider" />
  </providers>
</siteMap>

动态节点提供程序:

代码语言:javascript
复制
DynamicNode node = new DynamicNode();
node.Attributes.Add("dynamicParameters", "id");
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-11-10 04:22:32

我使用的是1.x版。我在动态参数方面也遇到了类似的问题。

我不得不修改源代码-在MvcSiteMapNode.cs中做了一个更改。这是Url属性的新实现

代码语言:javascript
复制
    public override string Url
    {
        get
        {
            if (!string.IsNullOrEmpty(this.url))
                return this.url;

            RequestContext ctx;
            if (HttpContext.Current.Handler is MvcHandler)
                ctx = ((MvcHandler)HttpContext.Current.Handler).RequestContext;
            else
                ctx = new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData());

            var routeValues = new RouteValueDictionary(RouteValues);

            foreach (var key in DynamicParameters)
                routeValues.Add(key, ctx.RouteData.Values[key]);

            return new UrlHelper(ctx).Action(Action, Controller, routeValues);
        }
        set
        {
            this.url = value;
        }
    }

注意dynamicParameters的实际值是如何添加到routeValues集合中的。

上面的更改允许我在站点地图中定义动态参数(如'id'),并创建带有Account/User/Edit/23等链接的面包屑。

我简要地看了一下2.x版,你应该能够应用类似的补丁。希望它能帮到你。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4137855

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档