要使用自定义参数(例如“id”),您必须配置 MvcSiteMapProvider 以将它们考虑在内。有 2 个选项 - 您可以为每个控制器操作配置 1 个节点(如您所做的那样),或者您可以为每个路由值组合配置 1 个节点(在您的情况下,每个 id 1 个节点)。
有一篇关于此主题的详细文章以及名为How to Make MvcSiteMapProvider Remember a User's Position 的可下载演示。这 2 个 StackOverflow 答案也可能会有所帮助。
CRUD 示例
但这里是读者的摘要版本。对于只对登录用户可用的 CRUD 操作(没有搜索引擎会看到),最好的方法是使用preservedRouteParameters 来强制一组节点匹配每条记录。
构建节点
首先要做的事情。让我们用索引、详细信息、创建、编辑和删除来做一个完整的例子,只是为了概述如果你使用它们会去哪里。您当然可以将您的实现限制为您需要的功能,如果您愿意,您可以将其更改为使用 MvcSiteMapNodeAttribute。但是我在这里用 XML 显示它们,以便您更容易在脑海中描绘它们。第一件事是适当地安排节点,以便您的面包屑路径正确显示当前位置。
<mvcSiteMapNode title="Home" controller="Home" action="Index" key="Home">
<mvcSiteMapNode title="Internal Mail Delivery Days" controller="InternalMailCalendar" action="Index" key="InternalMailCalendar">
<mvcSiteMapNode title="Create" controller="InternalMailCalendar" action="Create" visibility="SiteMapPathHelper,!*"/>
<mvcSiteMapNode title="Details" controller="InternalMailCalendar" action="Details" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id">
<mvcSiteMapNode title="Edit" controller="InternalMailCalendar" action="Edit" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id"/>
<mvcSiteMapNode title="Delete" controller="InternalMailCalendar" action="Delete" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id"/>
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMapNode>
因此,导航您的节点在面包屑路径中看起来像这样。
-
首页 > 内部邮件递送天数(显示所有记录的列表)
-
首页 > 内部邮件递送天数 > 创建(创建新记录的页面)
-
首页 > 内部邮件递送天数 > 记录 1(查看记录的页面 - 只读)
-
首页 > 内部邮件递送天数 > 记录 1 > 编辑(编辑记录的页面)
-
主页 > 内部邮件递送天数 > 记录 1 > 删除(要从中删除记录的页面)
这就是我们的目标,但我们还没有做到。在我们的节点上使用preservedRouteParameters="id",您现在可以看到它们在导航页面时将匹配当前请求。请注意,在使用preservedRouteParameters 时,您必须在您的网站内容中提供从记录到记录的导航,因为菜单不会显示记录。通常这是通过显示所有记录的网格以及指向相应命令(详细信息、编辑、删除等)的链接来完成的。
还有 2 件额外的事情需要处理 - 动态设置节点的标题并从菜单中隐藏与特定记录相关的节点。为什么?因为在使用preservedRouteParameters 时,不可能在MvcSiteMapProvider 中显示所有记录的列表——您只能获取当前记录。因此,我们得到的唯一东西就是面包屑路径。可以列出所有内容,但前提是您将每个记录的节点添加到 MvcSiteMapProvider 并明确设置每个记录的“id”,但这不是我们在此示例中所做的。
可见性
接下来,让我们关注可见性。如您所见,我已经将可见性属性中的过滤器设置为visibility="SiteMapPathHelper,!*"。这将告诉 FilteredSiteMapNodeVisibility 提供程序仅在 SiteMapPath HTML 帮助程序上显示节点,但在其他任何地方隐藏它。
但我们还需要做 2 件事才能让可见性发挥作用。我们需要将 FilteredSiteMapNodeVisibilityProvider 设置为默认值,并且我们需要关闭 Visibility Affects Descendants 设置。如果使用内部 DI,这些都可以在 web.config appSettings 中完成,如下所示。
<add key="MvcSiteMapProvider_DefaultSiteMapNodeVisibiltyProvider" value="MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider"/>
<add key="MvcSiteMapProvider_VisibilityAffectsDescendants" value="false"/>
如果使用外部 DI,您可以分别在 SiteMapNodeVisibilityProviderStrategy 和 SiteMapBuilderSet 的构造函数上配置这些设置。
// Visibility Providers
this.For<ISiteMapNodeVisibilityProviderStrategy>().Use<SiteMapNodeVisibilityProviderStrategy>()
.Ctor<string>("defaultProviderName").Is("MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider");
// Configure the builder sets
this.For<ISiteMapBuilderSetStrategy>().Use<SiteMapBuilderSetStrategy>()
.EnumerableOf<ISiteMapBuilderSet>().Contains(x =>
{
x.Type<SiteMapBuilderSet>()
.Ctor<string>("instanceName").Is("default")
.Ctor<bool>("securityTrimmingEnabled").Is(securityTrimmingEnabled)
.Ctor<bool>("enableLocalization").Is(enableLocalization)
.Ctor<bool>("visibilityAffectsDescendants").Is(false)
.Ctor<bool>("useTitleIfDescriptionNotProvided").Is(useTitleIfDescriptionNotProvided)
.Ctor<ISiteMapBuilder>().Is(builder)
.Ctor<ICacheDetails>().Is(cacheDetails);
});
标题
最后但同样重要的是,我们需要修复节点的标题,以便每次切换记录时它都会更改。这将确保我们在面包屑中看到我们所在记录的名称或标题,而不是在 XML 的 title 属性中设置的内容。
完成此操作的最简单方法是使用 SiteMapTitleAttribute。该属性可以添加到您的操作方法中。
<SiteMapTitle("Name", Target = AttributeTarget.ParentNode)> _
Function Edit(ByVal id As Integer) As ActionResult
If id > 0 Then
Dim obj = Mapper.Map(Of InternalMailCalendarViewModel)(_repositoryForIntMailCalendar.FindSingleByCondition(Function(x) x.ID = id))
If obj IsNot Nothing Then
Return View(obj)
End If
End If
Throw New HttpException(404, "Invalid Calendar ID")
End Function
此示例假定您的模型(变量 obj)具有名为“Name”的属性。该属性可以任意命名,它只需要匹配 SiteMapTitle 属性的配置。第二个参数表示我们希望当前节点的父节点改变标题。请记住,在上面的示例中,我们希望编辑面包屑看起来像这样:
主页 > 内部邮件递送天数 > 记录 1 > 编辑
换句话说,我们不希望编辑节点的标题发生变化,我们希望将“记录 1”的名称更改为当前记录的名称。只需确保将 Target 参数从 Details 节点中移除,因为在该节点上,我们需要动态更改当前标题,而不是父节点。
重要提示
使用preservedRouteParameters 有一个副作用,您需要注意——它会将当前请求中的“id”复制到配置它的所有 可见节点中。重复使用路由值“id”是可以的,只要它对所有可见的节点总是意味着相同的事情。如果您想要同时显示需要参数的另一级节点,则必须将其命名为不同于原始参数的名称(在本例中为“id”),以便可以将值命名为分开。
此外,您必须(手动)确保构建所有可见 URL 所需的所有值在每个请求的 URL 中都可用,即使这意味着在 URL 中添加您的应用程序不需要的额外信息.