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

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

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

商店/ 5 /产品/编辑/ 23

url模式的位置是:

存储/ {STOREID} / {控制器} / {行动} / {ID}

当ID被省略时(即“新”动作),它可以正常工作。 但是当指定ID时,它与路径不匹配,并且我的面包屑(使用SiteMapPath帮助程序)是空白的。

我的站点地图:(已删除)

         

地区注册:

 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中创建子节点作为动态节点的子节点。 这根本不起作用,最终成为“家”的孩子。 我会在其中放置一个ParentKey属性,除了这些将在每个商店重复,因此将有多个父键

               

第二次尝试:

看起来下一个选择就是在我的DynamicNodeProvider中添加子节点。 除了具有动态参数的节点外,这种方法效果更好

(以下内容为了便于说明而修改……)

 public class StoreAreaNodeProvider : IDynamicNodeProvider { public IEnumerable GetDynamicNodeCollection() { var nodes = new List(); 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; } } 

综上所述

工作: 商店/ 5 /产品/新
不起作用: 商店/ 5 /产品/编辑/ 23
对于url格式: 商店/ {storeID} / {controller} / {action} / {id}

我希望能做什么:

 editNode.Attributes.Add("isDynamic", "true"); editNode.Attributes.Add("dynamicParameters", "id"); 

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

希望我能正确地解释,并没有用信息压倒你。 谢谢!


更新:

以下是基于Jakub答案的解决方案。

在MvcSiteMapProvider 2.x中,您可以自己实现ISiteMapNodeUrlResolver,而不必修改源代码。 所以我基本上补充了拥有dynamicParameters属性的能力

类:

 namespace ControlPanel { public class CustomSiteMapNodeUrlResolver : ISiteMapNodeUrlResolver { public virtual string ResolveUrl(MvcSiteMapNode mvcSiteMapNode, string area, string controller, string action, IDictionary 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文件:

       

动态节点提供者:

 DynamicNode node = new DynamicNode(); node.Attributes.Add("dynamicParameters", "id"); 

我使用的是1.x版。 我有动态参数的类似问题。

我不得不修改源代码 – 在MvcSiteMapNode.cs中进行了更改。 这是Url属性的新实现

  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集合中。

上述更改允许我在站点地图中定义动态paremteres(如’id’)并使用Account / User / Edit / 23等链接创建面包屑。

我简要介绍了版本2.x,您应该能够应用类似的补丁。 希望它能帮到你……