【问题标题】:Dynamic Url - MVCSiteMapProvider Not Working动态网址 - MVCSiteMapProvider 不工作
【发布时间】:2014-07-10 02:01:28
【问题描述】:

我在 mvc.sitemap 文件中有以下代码(使用 mvcsitemapprovider mvc3):

 <?xml version="1.0" encoding="utf-8" ?>
   <mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0"
        xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd">

  <mvcSiteMapNode title="Home" controller="Home" action="Index" key="Home">
<mvcSiteMapNode title="Internal Mail Delivery Days - Display" controller="InternalMailCalendar" action="Index" key="InternalMailCalendar"  />
<mvcSiteMapNode title="Internal Mail Delivery Days - Create" controller="InternalMailCalendar" action="Create" />
 </mvcSiteMapNode>

 </mvcSiteMap>

我也在调用这个函数来添加面包屑:

<MvcSiteMapNode(Title:="Edit", ParentKey:="InternalMailCalendar")> _
    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

但仅针对此动态网址,面包屑中不会显示任何内容。请问有什么想法吗?

【问题讨论】:

    标签: vb.net asp.net-mvc-3 mvcsitemapprovider


    【解决方案1】:

    要使用自定义参数(例如“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 中添加您的应用程序不需要的额外信息.

    【讨论】:

    • 感谢您的回复。我所有的控制器都存在于他的主要 MVC 项目中。 useexternaldicontainer 设置为 false,scanassembliesforsitemapnodes 设置为 true,includeassembliesforscan 设置为正确的程序集。你觉得还有什么我想念的吗?因为我已经进行了这些更改,但仍然无法正常工作。
    • 仍然无法正常工作。我现在什至在这个问题上设置了赏金。
    • 我卸载了 sitemapprovider 并重新安装了它,现在它抛出了关于命名空间的错误。我正在使用 vb.net,它引入了 cshtml 模板,我需要将它们转换为 vbhtml 吗?
    • 我不完全确定您是否需要转换模板,但这样做不会有什么坏处。不过,我不认为命名空间问题是相关的。确保安装了依赖项 MvcSiteMapProvider.Core 和(尤其是)MvcSiteMapProvider.Web。如果是,则将 MvcSiteMapProvider 安装到一个空白 MVC 项目中,并将 &lt;system.web.webPages.razor&gt; 部分中 /Views/Web.config 中的命名空间导入复制到您的项目中。
    猜你喜欢
    • 1970-01-01
    • 2018-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-29
    • 2021-04-27
    • 2013-08-17
    • 2012-03-15
    相关资源
    最近更新 更多