创建子节点在MvcSiteMapProvider一个DynamicNode具有动态参数 [英] Creating child nodes for a DynamicNode in MvcSiteMapProvider that have dynamic parameters

查看:1020
本文介绍了创建子节点在MvcSiteMapProvider一个DynamicNode具有动态参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用MvcSiteMapProvider 2.2.1(HTTP://mvcsitemap.$c$cplex.com),以及时遇到的(使用dynamicNodeProvider)当那些孩子们有一个动态参数(动态节点下创建子问题ID)。

我失去面包屑以下路线:

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

其中URL模式是:

商店/ {STOREID} / {控制器} / {行动} / {ID}

当ID被冷落它工作正常(即新操作)。但是指定该ID时,它不匹配的路线,和我的面包屑(使用的SiteMapPath助手)是空白的。

我的网站地图:(简写)

 <?XML版本=1.0编码=UTF-8&GT?;
< mvcSiteMap的xmlns =HTTP://mvcsitemap.$c$cplex.com/schemas/MvcSiteMap-File-2.0>
    < mvcSiteMapNode标题=家控制器=仪表盘行动=索引changeFrequency =始终updatePriority =正常>
        < mvcSiteMapNode标题=我的帐户控制器=帐户行动=索引键=帐户/>
        < mvcSiteMapNode标题=我的店面积=专卖店控制器=家行动=索引visibilityProvider =ControlPanel.Areas.Stores.StoreAreaVisibilityProvider,ControlPanel控制>
            < mvcSiteMapNode标题=商店行动=索引dynamicNodeProvider =ControlPanel.Areas.Stores.StoreAreaNodeProvider,ControlPanel控制/>
        < / mvcSiteMapNode>
    < / mvcSiteMapNode>
< / mvcSiteMap>

区报名方式:

 公共覆盖无效RegisterArea(AreaRegistrationContext上下文)
{
        context.MapRoute(
            Store_Index
            专卖店,
            新{行动=索引,控制器=家},
            新的String [] {ControlPanel.Areas.Stores.Controllers}
            );        context.MapRoute(
            Store_default
            存储/ {STOREID} / {控制器} / {行动} / {ID}
            新{行动=索引,控制器=管理,ID = UrlParameter.Optional},
            新{STOREID = @\\ D +},
            新的String [] {ControlPanel.Areas.Stores.Controllers}
        );
    }

第一次尝试:

我想的第一件事就是建立孩子正确的XML网站地图的动态节点的子节点。这并没有在所有的工作,而这些最终成为家的孩子们。我就摆在那里一个ParentKey属性,除了这些将每家店的重复,因此将有多个parentkeys

 <?XML版本=1.0编码=UTF-8&GT?;
< mvcSiteMap的xmlns =HTTP://mvcsitemap.$c$cplex.com/schemas/MvcSiteMap-File-2.0>
  < mvcSiteMapNode标题=家控制器=仪表盘行动=索引changeFrequency =始终updatePriority =正常>
    < mvcSiteMapNode标题=我的帐户控制器=帐户行动=索引键=帐户/>
    < mvcSiteMapNode标题=我的店面积=专卖店控制器=家行动=索引visibilityProvider =ControlPanel.Areas.Stores.StoreAreaVisibilityProvider,ControlPanel控制>
      < mvcSiteMapNode标题=商店行动=索引dynamicNodeProvider =ControlPanel.Areas.Stores.StoreAreaNodeProvider,ControlPanel控制>
        < mvcSiteMapNode标题=产品面积=专卖店控制器=产品的行动=指数>
          < mvcSiteMapNode标题=编辑面积=专卖店控制器=产品的行动=编辑/>
          < mvcSiteMapNode标题=新面积=专卖店控制器=产品的行动=编辑/>
        < / mvcSiteMapNode>
      < / mvcSiteMapNode>
    < / mvcSiteMapNode>
  < / mvcSiteMapNode>
< / mvcSiteMap>

第二次尝试:

这似乎下一个选项就是刚才添加的子节点就在我的DynamicNodeProvider。这个工作除了那些有动态参数的节点要好得多。

(以下被修改为便于说明...)

 公共类StoreAreaNodeProvider:IDynamicNodeProvider
{
    公共IEnumerable的< D​​ynamicNode> GetDynamicNodeCollection()
    {
        VAR节点=新的List< D​​ynamicNode>();        的foreach(VAR店repo.GetStores())
        {
            DynamicNode节点=新DynamicNode();
            node.Title = store.Name;
            node.Area =专卖店
            node.Controller =管理;
            node.Action =指数;
            node.RouteValues​​.Add(STOREID,store.StoreID);
            node.Key =Store_+ store.StoreID.ToString();            nodes.Add(节点);            //节点的子
            DynamicNode productsNode =新DynamicNode();
            productsNode.Title =产品;
            productsNode.Area =专卖店
            productsNode.Controller =产品;
            productsNode.Action =指数;
            productsNode.RouteValues​​.Add(STOREID,store.StoreID);
            productsNode.ParentKey =的String.Format(Store_ {0},store.StoreID.ToString());
            productsNode.Key =的String.Format(Store_ {0} _产品展示,store.StoreID.ToString());            nodes.Add(productsNode);            // productsNode儿童
            DynamicNode editNode =新DynamicNode();
            editNode.Title =编辑;
            editNode.Area =专卖店
            editNode.Action =编辑;
            editNode.Controller =产品;
            editNode.RouteValues​​.Add(STOREID,store.StoreID);
            //我不能添加RouteValueID在这里,因为它是动态
            //我会通过每一个产品此店与do循环
            //另一个动态节点商,但似乎非常低效和愚蠢
            editNode.ParentKey =的String.Format(Store_ {0} _产品展示,store.StoreID.ToString());
            editNode.Attributes.Add(知名度,SiteMapPathHelper,*!);            nodes.Add(editNode);
        }        返回节点;
    }
}

总结

不工作:商店/ 5 /产品/新的结果
不工作:商店/ 5 /产品/编辑/ 23 的结果
对于URL模式:商店/ {STOREID} / {控制器} / {行动} / {ID}

我想能够做到:

  editNode.Attributes.Add(isDynamic,真);
editNode.Attributes.Add(dynamicParameters,ID);

我怎么能模拟天生老MvcSiteMapProvider的dynamicParameters这是一个dynamicNode的子节点上的属性?基本上我需要它来匹配路由时忽略了ID路线的价值。

希望我解释说,正确的,并没有与信息压倒你。谢谢!


更新:

下面是基于的Jakub的回答为我工作的解决方案。

在MvcSiteMapProvider 2.x中,你可以做,而不必修改源自己的实现ISiteMapNodeUrlResolver的。所以我基本上有dynamicParameters属性的能力重新添加

类:

 命名空间ControlPanel控制
{
    公共类CustomSiteMapNodeUrlResolver:ISiteMapNodeUrlResolver
    {
        公共虚拟字符串RESOLVEURL(MvcSiteMapNode mvcSiteMapNode,串区,串控制器,字符串操作,IDictionary<字符串对象> routeValues​​)
        {
            RequestContext的CTX;
            如果(HttpContext.Current.Handler是MvcHandler)
                CTX =((MvcHandler)HttpContext.Current.Handler).RequestContext;
            其他
                CTX =新的RequestContext(新HttpContextWrapper(HttpContext.Current),新的RouteData());            //开始增加code
            如果(mvcSiteMapNode [dynamicParameters]!= NULL)
            {
                的foreach(在mvcSiteMapNode [dynamicParameters]变种项目。斯普利特(新的char [] {','},StringSplitOptions.RemoveEmptyEntries))
                {
                    变种DP = item.Trim();
                    routeValues​​ [大] = ctx.RouteData.Values​​ [DP]
                }
            }
            //末尾加上code            返回新UrlHelper(CTX).Action(动作,控制器,新RouteValueDictionary(routeValues​​));
        }
    }
}

的Web.config:

 <站点地图defaultProvider =MvcSiteMapProvider启用=真>
  <供应商>
    <清/>
    <添加名称=MvcSiteMapProvider
         类型=MvcSiteMapProvider.DefaultSiteMapProvider,MvcSiteMapProvider
         siteMapFile =〜/ Mvc.Sitemap
         securityTrimmingEnabled =真
         attributesToIgnore =知名度,dynamicParameters
         scanAssembliesForSiteMapNodes =真
         siteMapNodeUrlResolver =ControlPanel.CustomSiteMapNodeUrlResolver,ControlPanel控制
         siteMapNodeVisibilityProvider =MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider,MvcSiteMapProvider/>
  < /供应商>
< /网站地图>

动态节点提供者:

  DynamicNode节点=新DynamicNode();
node.Attributes.Add(dynamicParameters,ID);


解决方案

我使用1.x版本。
我曾与动态参数类似的问题。

我不得不修改源$ C ​​$ C - 作出MvcSiteMapNode.cs的变化。这是新实施Url属性的

 公众覆盖字符串URL
    {
        得到
        {
            如果(!string.IsNullOrEmpty(this.url))
                返回this.url;            RequestContext的CTX;
            如果(HttpContext.Current.Handler是MvcHandler)
                CTX =((MvcHandler)HttpContext.Current.Handler).RequestContext;
            其他
                CTX =新的RequestContext(新HttpContextWrapper(HttpContext.Current),新的RouteData());            VAR routeValues​​ =新RouteValueDictionary(RouteValues​​);            的foreach(在DynamicParameters VAR键)
                routeValues​​.Add(键,ctx.RouteData.Values​​ [关键]);            返回新UrlHelper(CTX).Action(动作,控制器,routeValues​​);
        }
        组
        {
            this.url =价值;
        }
    }

注意如何实际dynamicParameters的值被添加到收藏routeValues​​

上面的变化让我在站点地图定义动态paremteres(如ID),并创建与像帐户/用户链接面包/编辑/ 23。

我把在2.x版本简单的介绍一下,你应该能够运用类似的补丁。
希望它会帮助你...

I am using MvcSiteMapProvider 2.2.1 (http://mvcsitemap.codeplex.com), and am having a problem with creating children under a dynamic node (using a dynamicNodeProvider) when those children have a dynamic parameter (id).

I am losing breadcrumbs for the following route:

Stores/5/Products/Edit/23

where the url pattern is:

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

It works fine when the ID is left out (ie the "New" action). But when the ID is specified, it doesn't match the route, and my breadcrumbs (using the SiteMapPath helper) is blank.

My Sitemap: (abreviated)

<?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>

Area Registration:

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" }
        );
    }

First Attempt:

The first thing I tried was to create the child nodes right in the sitemap xml as children of the dynamic node. This didn't work at all, and these ended up being children of "Home". I would put a ParentKey attribute in there, except these will be repeated per store and thus there will be multiple parentkeys

<?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>

Second Attempt:

It seemed the next option was to just add the child nodes right in my DynamicNodeProvider. This worked much better except for the nodes that had dynamic parameters

(the below is modified for ease of explanation...)

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;
    }
}

In Summary

Does Work: Stores/5/Products/New
Doesn't Work: Stores/5/Products/Edit/23
For Url Pattern: Stores/{storeID}/{controller}/{action}/{id}

What I would like to be able to do:

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

How can I mimick the old MvcSiteMapProvider's dynamicParameters attribute on a node that is a child of a dynamicNode? Basically I need it to ignore the "id" route value when matching routes.

Hopefully I explained that properly, and didn't overwhelm you with information. Thanks!


UPDATE:

Here is the solution that worked for me based on Jakub's answer.

In MvcSiteMapProvider 2.x, you can make your own implementation of ISiteMapNodeUrlResolver instead of having to modify the source. So I basically added back in the ability to have the dynamicParameters attribute

Class:

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:

<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>

Dynamic Node Provider:

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

解决方案

I am using version 1.x. I had a similar problem with dynamic parameters.

I had to modify the source code - made a change in MvcSiteMapNode.cs. This is the new implementation of Url property

    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;
        }
    }

Notice how actual values of dynamicParameters are added to routeValues collection.

The above change allowed me to define dynamic paremteres in sitemap (like 'id') and create breadcrumbs with links like Account/User/Edit/23.

I took a brief look at version 2.x and you should be able to apply similar patch. Hope it will help you...

这篇关于创建子节点在MvcSiteMapProvider一个DynamicNode具有动态参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆