gpt4 book ai didi

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

转载 作者:IT王子 更新时间:2023-10-29 04:44:47 25 4
gpt4 key购买 nike

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

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

Stores/5/Products/Edit/23

url 模式在哪里:

商店/{storeID}/{controller}/{action}/{id}

当 ID 被遗漏时它工作正常(即“新建”操作)。但是当指定 ID 时,它与路由不匹配,我的面包屑(使用 SiteMapPath 助手)是空白的。

我的站点地图:(缩写)

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

区域注册:

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

第一次尝试:

我尝试的第一件事是在站点地图 xml 中创建子节点作为动态节点的子节点。这根本行不通,这些最终成为“家”的 child 。我会在那里放一个 ParentKey 属性,除了这些将在每个商店重复,因此会有多个父键

<?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 中添加子节点。除了具有动态参数的节点之外,这工作得更好

(为便于解释,修改了以下...)

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

总结

有效:Stores/5/Products/New
不起作用:Stores/5/Products/Edit/23
对于 Url 模式:Stores/{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<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>

动态节点提供者:

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

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

我简单看了一下 2.x 版本,你应该可以应用类似的补丁。希望对您有所帮助...

关于c# - 在具有动态参数的 MvcSiteMapProvider 中为 DynamicNode 创建子节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4137855/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com