设置:
我正在使用带有 mvcSiteMapProvider 的 ASP.NET MVC 4 来管理我的菜单。
我有一个自定义菜单生成器,它评估一个节点是否在当前分支上(即,如果它SiteMap.CurrentNode
是 CurrentNode 或 CurrentNode 是否嵌套在它下面)。代码包含在下面,但本质上是检查每个节点的 url 并将其与 currentnode 的 url 进行比较,直至 currentnodes “家谱”。
我的自定义菜单构建器使用 CurrentBranch 来添加一个突出显示 CurrentBranch 上的菜单项的类。
问题:
我的自定义菜单工作正常,但我发现mvcSiteMapProvider
似乎并没有以一致的方式评估url
的:CurrentNode
当两个节点指向同一个动作并且仅通过动作的一个参数来区分时,SiteMap.CurrentNode 似乎没有使用正确的路由(它忽略区分参数并默认为映射到定义的动作的第一个路由节点)。
问题示例:
在我拥有的应用程序中Members
。
成员具有MemberStatus
可以是“未处理”、“活动”或“非活动”的字段。要更改 MemberStatus,我有一个ProcessMemberController
名为 Admin 的区域。处理是使用 上的Process
操作完成的ProcessMemberController
。
我的 mvcSiteMap 有两个节点都映射到Process
动作。它们之间的唯一区别是alternate
参数(例如我客户的域语义),在一种情况下具有“已处理”的值,而在另一种情况下具有“未处理”的值:
节点:
<mvcSiteMapNode title="Process" area="Admin" controller="ProcessMembers" action="Process" alternate="Unprocessed" />
<mvcSiteMapNode title="Change Status" area="Admin" controller="ProcessMembers" action="Process" alternate="Processed" />
路线:
到这两个节点的对应路由是(同样,唯一能区分它们的是alternate 参数的值):
context.MapRoute(
"Process_New_Members",
"Admin/Unprocessed/Process/{MemberId}",
new { controller = "ProcessMembers",
action = "Process",
alternate="Unprocessed",
MemberId = UrlParameter.Optional }
);
context.MapRoute(
"Change_Status_Old_Members",
"Admin/Members/Status/Change/{MemberId}",
new { controller = "ProcessMembers",
action = "Process",
alternate="Processed",
MemberId = UrlParameter.Optional }
);
什么有效:
Html.ActionLink 助手使用路由并生成我期望的 url:
@Html.ActionLink("Process", MVC.Admin.ProcessMembers.Process(item.MemberId, "Unprocessed")
// Output (alternate="Unprocessed" and item.MemberId = 12): Admin/Unprocessed/Process/12
@Html.ActionLink("Status", MVC.Admin.ProcessMembers.Process(item.MemberId, "Processed")
// Output (alternate="Processed" and item.MemberId = 23): Admin/Members/Status/Change/23
在这两种情况下,输出都是正确的,正如我所料。
什么不起作用:
假设我的请求涉及第二个选项,即 ,/Admin/Members/Status/Change/47
对应于 alternate = "Processed" 和 MemberId 47。
调试我的静态 CurrentBranch 属性(见下文),我发现 SiteMap.CurrentNode 显示:
PreviousSibling: null
Provider: {MvcSiteMapProvider.DefaultSiteMapProvider}
ReadOnly: false
ResourceKey: ""
Roles: Count = 0
RootNode: {Home}
Title: "Process"
Url: "/Admin/Unprocessed/Process/47"
即,对于 /Admin/Members/Status/Change/47 的请求 url,SiteMap.CurrentNode.Url
计算结果为/Admin/Unprocessed/Process/47
. 即,它忽略了alternate
参数并使用了错误的路线。
CurrentBranch 静态属性:
/// <summary>
/// ReadOnly. Gets the Branch of the Site Map that holds the SiteMap.CurrentNode
/// </summary>
public static List<SiteMapNode> CurrentBranch
{
get
{
List<SiteMapNode> currentBranch = null;
if (currentBranch == null)
{
SiteMapNode cn = SiteMap.CurrentNode;
SiteMapNode n = cn;
List<SiteMapNode> ln = new List<SiteMapNode>();
if (cn != null)
{
while (n != null && n.Url != SiteMap.RootNode.Url)
{
// I don't need to check for n.ParentNode == null
// because cn != null && n != SiteMap.RootNode
ln.Add(n);
n = n.ParentNode;
}
// the while loop excludes the root node, so add it here
// I could add n, that should now be equal to SiteMap.RootNode, but this is clearer
ln.Add(SiteMap.RootNode);
// The nodes were added in reverse order, from the CurrentNode up, so reverse them.
ln.Reverse();
}
currentBranch = ln;
}
return currentBranch;
}
}
问题:
我究竟做错了什么?
正如我所料,这些路线由 Html.ActionLlink 解释,但不像我所料那样由 SiteMap.CurrentNode 评估。换句话说,在评估我的路线时,SiteMap.CurrentNode 忽略了可区分的备用参数。