mvcSitemap 和多条路线

mvcSitemap and multiple routes

我正在尝试使用 MVC 站点地图为我的应用程序创建面包屑路径。我有多个路由到用户控制器,需要为每个路由保留面包屑。 mvcSiteMap如何将每个节点映射到路由?

我有以下进入用户的可能途径:

/User/{action}/{userid}

/User/{groupid}/{action}/{userid}

我分别想要以下面包屑路径:

App Root > Users > {User Name} > {Action}

App Root > Group Management > {Group Name} > {User Name} > {Action}

上面的第一条路线足够直截了当,我用 [SiteMapTitle("Mail")] 修饰了 Details 控制器以显示对象 Mail 属性而不是“Details”,并且编辑用 [SiteMapTitle( "Mail", Target = AttributeTarget.ParentNode)] 编辑时保留邮箱地址。

但是,在使用第二条路线时,我无法弄清楚如何完成所有这些操作。面包屑路径根本不显示任何内容。组部分中的用户部分似乎什么都不做。实现此目标的最佳方法是什么?

Mvc.Sitemap:

    <mvcSiteMapNode title="User Management" controller="User" action="Index">
      <mvcSiteMapNode title="Details" action="Details" controller="User" preservedRouteParameters="id">
        <mvcSiteMapNode title="Edit" action="Edit" controller="User" preservedRouteParameters="id"/>
      </mvcSiteMapNode>
    </mvcSiteMapNode>

    <mvcSiteMapNode title="Group Management" controller="Group" action="Index">
      <mvcSiteMapNode title="Details" action="Details" controller="Group" preservedRouteParameters="id">
        <mvcSiteMapNode title="Edit" action="Edit" controller="Group" preservedRouteParameters="id"/>

        <mvcSiteMapNode title="Users" controller="User" action="Index" preservedRouteParameters="groupid">
          <mvcSiteMapNode title="Details" action="Details" controller="User" preservedRouteParameters="id, groupid">
            <mvcSiteMapNode title="Edit" action="Edit" controller="User" preservedRouteParameters="id, groupid"/>
            <mvcSiteMapNode title="Manage" action="Manage" controller="User" preservedRouteParameters="id, groupid"/>
          </mvcSiteMapNode>
        </mvcSiteMapNode>


      </mvcSiteMapNode>
      <mvcSiteMapNode title="New" action="Create" controller="Group" />
    </mvcSiteMapNode>
    ...
  </mvcSiteMapNode>

路线:

routes.MapRoute("ByGroup", "User/{groupid}/{action}/{id}",
                        new { controller = "User", action = "Index", id = UrlParameter.Optional }, new { groupid = new GuidConstraint() });

routes.MapRoute("ByGroup2", "User/{groupid}/{action}/{id}",
                        new { controller = "User", action = "Index", id = UrlParameter.Optional, groupid = UrlParameter.Optional }, new { groupid = new GuidConstraint() });


routes.MapRoute("User", "User/{action}/{id}",
                        new { controller = "User", action = "Index", id = UrlParameter.Optional });

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

节点:

<mvcSiteMapNode title="User Management" controller="User" action="Index" route="Default">
    <mvcSiteMapNode title="Details" action="Details" controller="User" route="Default" preservedRouteParameters="id">
        <mvcSiteMapNode title="Edit" action="Edit" controller="User" route="Default" preservedRouteParameters="id"/>
    </mvcSiteMapNode>
</mvcSiteMapNode>

<mvcSiteMapNode title="Group Management" controller="Group" action="Index">
    <mvcSiteMapNode title="Details" action="Details" controller="Group" preservedRouteParameters="groupid">
        <mvcSiteMapNode title="Edit" action="Edit" controller="Group" preservedRouteParameters="groupid"/>

        <mvcSiteMapNode title="Users" controller="User" action="Index" route="ByGroup" preservedRouteParameters="groupid">
            <mvcSiteMapNode title="Details" action="Details" controller="User" route="ByGroup" preservedRouteParameters="id, groupid">
                <mvcSiteMapNode title="Edit" action="Edit" controller="User" route="ByGroup" preservedRouteParameters="id, groupid"/>
                <mvcSiteMapNode title="Manage" action="Manage" controller="User" route="ByGroup" preservedRouteParameters="id, groupid"/>
            </mvcSiteMapNode>
        </mvcSiteMapNode>

    </mvcSiteMapNode>
    <mvcSiteMapNode title="New" action="Create" controller="Group" />
</mvcSiteMapNode>

路线:

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

routes.MapRoute(
    name: "ByGroup",
    url: "User/{groupid}/{action}/{id}",
    defaults: new { controller = "User", action = "Index", id = UrlParameter.Optional },
    constraints: new { groupid = new GuidConstraint() });

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

说明

您在 ByGroup2 路线上定义了 2 个可选航段,这是不允许的。可选段必须位于 URL 的最右侧,并且后面不能跟必需的段。这可能会导致问题。

此外,我没有看到 ByGroup2 路线的任何实际用途。

/User/131f89da-0dca-40f0-bc99-41559d13fc7f/Edit/123 - matches ByGroup
/User/131f89da-0dca-40f0-bc99-41559d13fc7f/Index - matches ByGroup
/User/Edit/123 - matches User
/User/Index - matches User

我想不出可以匹配 ByGroup2 的情况。但是如果它 确实 匹配,你的参数将被放入不同的路由键,而不是它匹配 User 路由,这可能会造成混淆。

此外,您的 User 路线似乎没有在 Default 路线上添加任何内容。因此,您的路由配置可能看起来像这样并做完全相同的事情(减去路由值位置的混淆,这可能会给您带来问题)。

routes.MapRoute("ByGroup", "User/{groupid}/{action}/{id}",
                    new { controller = "User", action = "Index", id = UrlParameter.Optional }, new { groupid = new GuidConstraint() });

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

然后匹配看起来像这样。

/User/131f89da-0dca-40f0-bc99-41559d13fc7f/Edit/123 - matches ByGroup
/User/131f89da-0dca-40f0-bc99-41559d13fc7f/Index - matches ByGroup
/User/Edit/123 - matches Default
/User/Index - matches Default

但是,您的 preservedRouteParameters 也有问题。

<mvcSiteMapNode title="Details" action="Details" controller="Group" preservedRouteParameters="id">
    <mvcSiteMapNode title="Edit" action="Edit" controller="Group" preservedRouteParameters="id"/>

        <mvcSiteMapNode title="Users" controller="User" action="Index" preservedRouteParameters="groupid">
            <mvcSiteMapNode title="Details" action="Details" controller="User" preservedRouteParameters="id, groupid">
                <mvcSiteMapNode title="Edit" action="Edit" controller="User" preservedRouteParameters="id, groupid"/>
                <mvcSiteMapNode title="Manage" action="Manage" controller="User" preservedRouteParameters="id, groupid"/>
            </mvcSiteMapNode>
        </mvcSiteMapNode>
    </mvcSiteMapNode>
</mvcSiteMapNode>

要使 preservedRouteParameters 匹配多个级别,ancestor 节点的所有自定义路由值(在本例中为 idgroupid)必须被提供。此外,它们必须具有相同的含义。为此,id 必须始终通过节点一直引用同一实体,并且必须包含在每个 link 中,无论多深。您必须为群组实体选择与用户实体不同的路由键。

要清除此问题,您可以再更改一次路线以将所有信息放入所需的路线中。您已经完成大部分工作了 - 您只需要修复组节点的 ID。

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

routes.MapRoute(
    name: "ByGroup",
    url: "User/{groupid}/{action}/{id}",
    defaults: new { controller = "User", action = "Index", id = UrlParameter.Optional },
    constraints: new { groupid = new GuidConstraint() });

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

和节点:

<mvcSiteMapNode title="Details" action="Details" controller="Group" preservedRouteParameters="groupid">
    <mvcSiteMapNode title="Edit" action="Edit" controller="Group" preservedRouteParameters="groupid"/>

    <mvcSiteMapNode title="Users" controller="User" action="Index"  route="ByGroup" preservedRouteParameters="groupid">
        <mvcSiteMapNode title="Details" action="Details" controller="User" route="ByGroup" preservedRouteParameters="id, groupid">
        <mvcSiteMapNode title="Edit" action="Edit" controller="User" route="ByGroup" preservedRouteParameters="id, groupid"/>
    <mvcSiteMapNode title="Manage" action="Manage" controller="User" route="ByGroup" preservedRouteParameters="id, groupid"/>
</mvcSiteMapNode>

注意到 /Group/Index 节点下面的每条路由现在都有一个 groupid,并且 groupid 键总是指同一个实体?

此外,为了确保我们只匹配相关的路由,我们明确指定了它。如果我们不这样做,用户节点将是不明确的,因此您将得到错误的面包屑痕迹(第一个匹配的节点获胜)。

route="ByGroup"

使用上述配置,您需要将 link 构建到 UsersUsers/DetailsUsers/EditUsers/Manage,其中包括当前 groupid(当然还有当前用户 ID)。

@Html.ActionLink("Edit User", "Edit", "User", new { id = <userid>, groupid = <groupid> }, null)

然后当你导航到"Edit User" link时,groupid将在当前请求中,它将它提供给Users/Details节点,Group/Edit节点和 Group/Details 节点解析 URLs 以便您可以通过面包屑路径导航回这些位置。

有关另一个示例,请参阅代码下载中的 Forcing-A-Match-2-Levels 示例 of this article

没有组的用户部分将匹配 Default 路由,并在构建没有 groupid 的 URL 时显示适当的面包屑痕迹。

所以我们显式指定默认路由:

route="Default"

并像这样构建 URL:

@Html.ActionLink("Edit User", "Edit", "User", new { id = <userid> }, null)