MVCSiteMapProvider面包屑错误的父节点ID

时间:2014-02-21 16:36:48

标签: asp.net-mvc asp.net-mvc-5 sitemap mvcsitemapprovider

我有这个站点地图:

<mvcSiteMapNode title="Projects" controller="Projects" action="Index" key="Home" visibility="!*">
<mvcSiteMapNode title="Projects" controller="Projects" action="Index">
  <mvcSiteMapNode title="Project" controller="Projects" action="Details" preservedRouteParameters="id">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" preservedRouteParameters="id">
      <mvcSiteMapNode title="Edit Session" controller="Sessions" action="Edit" preservedRouteParameters="id"/>
    </mvcSiteMapNode>
  </mvcSiteMapNode>
</mvcSiteMapNode>
<mvcSiteMapNode title="My Account" controller="Account" action="ChangePassword" />
<mvcSiteMapNode title="Admin" controller="Admin" action="Index" >
  <mvcSiteMapNode title="Create User" controller="Admin" action="AddUser" />
  <mvcSiteMapNode title="Manage Users" controller="Admin" action="Users" />
</mvcSiteMapNode>

当我转到会话详细信息页面时,面包屑显示:

Projects > Project > Session

然而,项目链接(转到“项目详细信息”页面)使用与会话相同的ID,而不是它来自的项目。

我尝试将inheritedRouteParameters="id"添加到“会话详细信息”页面,但它没有改变任何内容。

修改 我添加了不同的savedRouteParameters,但现在“Project”链接回/ Projects / Details而没有附加id。

1 个答案:

答案 0 :(得分:3)

如果键名匹配,

savedRouteParameters总是复制当前请求的值,它不会假设“id”是什么。因此,如果在同时显示的2个节点上的savedRouteParameters中使用“id”,则需要确保它们具有相同的含义。

解决此问题的一种方法是为每种情况使用不同的密钥名称(例如,“projectId”和“sessionId”)。然后,您可以在子节点上保留它们,以便“记住”它所属的父节点。

<mvcSiteMapNode title="Project" controller="Projects" action="Details" preservedRouteParameters="projectId">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" preservedRouteParameters="projectId,sessionId">

您可能需要修改路由以使其生成符合您要求的URL,但为此,父ID必须是子节点的路由(通常是URL)的一部分。以下是与上述节点配置匹配的示例。

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "SessionRoute", 
            url: "Project/{projectId}/{sessionId}", 
            defaults: new { controller = "Sessions", action = "Details" });

        routes.MapRoute(
            name: "ProjectRoute", 
            url: "Project/{projectId}", 
            defaults: new { controller = "Projects", action = "Details" });

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

查看MvcSiteMapProvider-Forcing-A-Match-2-Levels项目in this demo,看看究竟如何做到这一点。请注意,添加路由是可选的 - 如果您不介意URL中的查询字符串参数,则可以始终使用默认路由。

如果这不适合您,则可以在一个节点参数上使用savedRouteParmeters组合,并明确设置另一个参数。

<mvcSiteMapNode title="Project" controller="Projects" action="Details" preservedRouteParameters="projectId">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" id="1" preservedRouteParameters="projectId">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" id="2" preservedRouteParameters="projectId">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" id="3" preservedRouteParameters="projectId">

或者您可以为您拥有的每个“id”组合创建一个节点。

<mvcSiteMapNode title="Project" controller="Projects" action="Details" id="1">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" id="1">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" id="2">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" id="3">
</mvcSiteMapNode>
<mvcSiteMapNode title="Project" controller="Projects" action="Details" id="2">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" id="4">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" id="5">
    <mvcSiteMapNode title="Session" controller="Sessions" action="Details" id="6">
</mvcSiteMapNode>

对于最后两个选项,通常最好使用DynamicNodeProvider填充动态数据,而不是用XML标记它们。

这些方法可以创建更干净的URL,但也会消耗更多的RAM。通常对于管理页面,最好使用稍微粗略的URL(savedRouteParmaters)并使用动态节点(和RAM)保存需要搜索引擎索引的页面。

inheritedRouteParameters仅用于从XML配置中的父节点继承值,并且在请求级别无效。

BTW - 您必须确保每个节点上都有唯一的路由值组合。在您的示例中,前2个节点具有完全相同的路由值,这意味着第二个节点永远不会匹配,因为第一个匹配总是获胜。