如何构建具有多个子站点地图的站点地图?

2024-05-01

我在用 MVC4、MvcSiteMapProvider v3.2.1(需要能够升级到v4)。

我的问题是应用程序很大。我想模块化应用程序并使模块可插拔。
由于站点地图已经很大,我想让站点地图也变得可插拔。
有没有办法在应用程序启动时使用根站点地图从多个 xml 文件加载节点来构建站点地图?

下面举个例子来解释一下:
原来的站点地图:

<?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-3.0"
            xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0 MvcSiteMapSchema.xsd"
            enableLocalization="true">

  <mvcSiteMapNode title="Home" controller="Home" action="Index">

    <mvcSiteMapNode title="Staff List" controller="Staff" action="List">
       <mvcSiteMapNode title="Create Staff" controller="Staff" action="Create"/>
       <mvcSiteMapNode title="Edit Staff" controller="Staff" action="Edit"/>
       <mvcSiteMapNode title="View Staff" controller="Staff" action="Details">
           <mvcSiteMapNode >
           ...
       </mvcSiteMapNode>
    </mvcSiteMapNode>

    <mvcSiteMapNode title="Client List" controller="Client" action="List">
       <mvcSiteMapNode title="Create Client" controller="Client" action="Create"/>
       <mvcSiteMapNode title="Edit Client" controller="Client" action="Edit"/>
       <mvcSiteMapNode title="View Client" controller="Client" action="Details">
           <mvcSiteMapNode >
           ...
       </mvcSiteMapNode>
    </mvcSiteMapNode>
   </mvcSiteMapNode>
</mvcSiteMap>

我想将站点地图拆分为:
根站点地图:

  <mvcSiteMapNode title="Home" controller="Home" action="Index">

    <subsitemap file="StaffSiteMap">// something like this.

    <subsitemap file="ClientSiteMap">// something like this.
   </mvcSiteMapNode>
</mvcSiteMap>

工作人员网站地图:

<mvcSiteMapNode title="Staff List" controller="Staff" action="List">
  <mvcSiteMapNode title="Create Staff" controller="Staff" action="Create"/>
  <mvcSiteMapNode title="Edit Staff" controller="Staff" action="Edit"/>
  <mvcSiteMapNode title="View Staff" controller="Staff" action="Details">
    <mvcSiteMapNode />
    ...
  </mvcSiteMapNode>
</mvcSiteMapNode>

客户网站地图:

<mvcSiteMapNode title="Client List" controller="Client" action="List">
  <mvcSiteMapNode title="Create Client" controller="Client" action="Create"/>
  <mvcSiteMapNode title="Edit Client" controller="Client" action="Edit"/>
  <mvcSiteMapNode title="View Client" controller="Client" action="Details">
    <mvcSiteMapNode >
      ...
    </mvcSiteMapNode>
  </mvcSiteMapNode>
</mvcSiteMapNode>

您的方法可能会导致您创建比您需要的更多的节点。除非在搜索引擎中索引 CRUD 操作很重要,否则有一个快捷方式。您可以使用一组节点来进行“索引”、“创建”、“编辑”、“删除”、“详细信息”并使用preservedRouteParameters强制它们匹配每个可能的“id”。

首先,您需要正确嵌套节点,以便它们在每种情况下都能显示正确的面包屑路径。

<mvcSiteMapNode title="Staff" controller="Staff" action="List">
    <mvcSiteMapNode title="Create New" action="Create" />
    <mvcSiteMapNode title="Details" action="Details" preservedRouteParameters="id">
        <mvcSiteMapNode title="Edit" action="Edit" preservedRouteParameters="id"/>
        <mvcSiteMapNode title="Delete" action="Delete" preservedRouteParameters="id"/>
    </mvcSiteMapNode>
</mvcSiteMapNode>

“编辑”、“删除”和“详细信息”节点都不会出现在菜单或其他控件中,因此您需要使用FilteredSiteMapNodeVisibilityProvider在这种情况下使它们不可见。您可以将默认可见性提供程序设置为FilteredSiteMapNodeVisibilityProvider在配置中,因此您不必在每个节点上设置它。您还应该设置VisibilityAffectsDescendants属性设置为 false 以确保每个节点始终打开和关闭,而不是在其父节点不可见时不可见。

内部 DI (web.config):

<appSettings>
    <add key="MvcSiteMapProvider_DefaultSiteMapNodeVisibiltyProvider" value="MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider"/>
    <add key="MvcSiteMapProvider_VisibilityAffectsDescendants" value="false"/>
</appSettings>

外部 DI(在 DI 模块中,所示的 StructureMap 示例):

bool visibilityAffectsDescendants = false;

// Module code omitted here...

// Visibility Providers
this.For<ISiteMapNodeVisibilityProviderStrategy>().Use<SiteMapNodeVisibilityProviderStrategy>()
    .Ctor<string>("defaultProviderName").Is("MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider");

要完成可见性,您需要设置visibility每个节点的属性。

<mvcSiteMapNode title="Staff" controller="Staff" action="List">
    <mvcSiteMapNode title="Create New" action="Create" visibility="SiteMapPathHelper,!*" />
    <mvcSiteMapNode title="Details" action="Details" preservedRouteParameters="id" visibility="SiteMapPathHelper,!*">
        <mvcSiteMapNode title="Edit" action="Edit" preservedRouteParameters="id" visibility="SiteMapPathHelper,!*"/>
        <mvcSiteMapNode title="Delete" action="Delete" preservedRouteParameters="id" visibility="SiteMapPathHelper,!*"/>
    </mvcSiteMapNode>
</mvcSiteMapNode>

此外,您可能需要设置“索引”节点的标题,以便它将显示当前记录的标题。你可以用SiteMapTitleAttribute在你的每一个行动方法中。

[SiteMapTitle("Name")]
public ActionResult Details(int id)
{
    using (var db = new EntityContext())
    {
        var model = (from staff in db.Staff
                    where staff.Id == id
                    select staff).FirstOrDefault();

        return View(model);
    }
}

假设您的 Staff 表中有一个名为“Name”的字段。您还需要在编辑和删除方法(获取和发布)中进行设置。但您还需要确保将属性目标设置为ParentNode因此它将覆盖“详细信息”节点的标题。

[SiteMapTitle("Name", Target = AttributeTarget.ParentNode)]
public ActionResult Edit(int id)
{
    using (var db = new EntityContext())
    {
        var model = (from staff in db.Staff
                     where staff.Id == id
                     select staff).FirstOrDefault();
        return View(model);
    }
}

[HttpPost]
[SiteMapTitle("Name", Target = AttributeTarget.ParentNode)]
public ActionResult Edit(int id, Staff staff)
{
    try
    {
        using (var db = new EntityContext())
        {
            var model = (from s in db.Staff
                         where s.Id == id
                         select s).FirstOrDefault();
            if (model != null)
            {
                model.Name = staff.Name;

                db.SaveChanges();
            }
        }

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

结果是您将得到虚假的面包屑,这些面包屑会根据选择的记录而变化。

Home > Staff 
Home > Staff > Create New 
Home > Staff > John Doe 
Home > Staff > John Doe > Edit 
Home > Staff > John Doe > Delete

有关可下载的工作演示,请参阅Forcing-A-Match项目中的代码下载如何让 MvcSiteMapProvider 记住用户的位置 https://web.archive.org/web/20160425143429/http://www.shiningtreasures.com/post/2013/09/02/how-to-make-mvcsitemapprovider-remember-a-user-position.

请注意,在 MvcSiteMapProvider 版本 3.x 中也可以执行此操作,您只需在siteMap/providers/add标记并忽略有关的部分VisibilityAffectsDescendants.

<siteMap defaultProvider="MvcSiteMapProvider" enabled="true">
    <providers>
        <clear/>
        <add name="MvcSiteMapProvider"
             type="MvcSiteMapProvider.DefaultSiteMapProvider, MvcSiteMapProvider"
             siteMapFile="~/Mvc.Sitemap"
             securityTrimmingEnabled="true"
             cacheDuration="5"
             enableLocalization="true"
             scanAssembliesForSiteMapNodes="true"
             excludeAssembliesForScan=""
             includeAssembliesForScan=""
             attributesToIgnore="bling,visibility"
             nodeKeyGenerator="MvcSiteMapProvider.DefaultNodeKeyGenerator, MvcSiteMapProvider"
             controllerTypeResolver="MvcSiteMapProvider.DefaultControllerTypeResolver, MvcSiteMapProvider" 
             actionMethodParameterResolver="MvcSiteMapProvider.DefaultActionMethodParameterResolver, MvcSiteMapProvider"
             aclModule="MvcSiteMapProvider.DefaultAclModule, MvcSiteMapProvider"
             routeMethod=""
             siteMapNodeUrlResolver="MvcSiteMapProvider.DefaultSiteMapNodeUrlResolver, MvcSiteMapProvider"
             siteMapNodeVisibilityProvider="MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider"
             siteMapProviderEventHandler="MvcSiteMapProvider.DefaultSiteMapProviderEventHandler, MvcSiteMapProvider"/>
    </providers>
</siteMap>

如果您仍然认为有必要将 SiteMap 组织成较小的文件,则在 3.x 版本中这是不可能的。如果您使用外部 DI 并重复以下步骤,则在 4.x 版本中可以在配置中使用多个 XML 文件XmlSiteMapNodeProvider同一个站点地图多次。以下是使用 StructureMap 执行此操作的方法。

// Prepare for our node providers
var rootXmlSource = this.For<IXmlSource>().Use<FileXmlSource>()
   .Ctor<string>("fileName").Is(HostingEnvironment.MapPath("~/Root.sitemap"));
var staffXmlSource = this.For<IXmlSource>().Use<FileXmlSource>()
   .Ctor<string>("fileName").Is(HostingEnvironment.MapPath("~/Staff.sitemap"));
var clientXmlSource = this.For<IXmlSource>().Use<FileXmlSource>()
   .Ctor<string>("fileName").Is(HostingEnvironment.MapPath("~/Client.sitemap"));

// Register the sitemap node providers
var siteMapNodeProvider = this.For<ISiteMapNodeProvider>().Use<CompositeSiteMapNodeProvider>()
    .EnumerableOf<ISiteMapNodeProvider>().Contains(x =>
    {
        x.Type<XmlSiteMapNodeProvider>()
            .Ctor<bool>("includeRootNode").Is(true)
            .Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
            .Ctor<IXmlSource>().Is(rootXmlSource);
        x.Type<XmlSiteMapNodeProvider>()
            .Ctor<bool>("includeRootNode").Is(false)
            .Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
            .Ctor<IXmlSource>().Is(staffXmlSource);
        x.Type<XmlSiteMapNodeProvider>()
            .Ctor<bool>("includeRootNode").Is(false)
            .Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
            .Ctor<IXmlSource>().Is(clientXmlSource);
        x.Type<ReflectionSiteMapNodeProvider>()
            .Ctor<IEnumerable<string>>("includeAssemblies").Is(includeAssembliesForScan)
            .Ctor<IEnumerable<string>>("excludeAssemblies").Is(new string[0]);
    });

请注意,每个 XML 文件仍然需要一个根节点,但如果 includeRootNode 参数为 false,则不会将其解析到 SiteMap 中。实际上,这与嵌套节点相同Staff.sitemap and Client.sitemap主页下方的文件Root.sitemap.

根站点地图

<?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"/>
</mvcSiteMap>

员工网站地图

<?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="Staff List" controller="Staff" action="List">
           <mvcSiteMapNode title="Create Staff" controller="Staff" action="Create"/>
           <mvcSiteMapNode title="Edit Staff" controller="Staff" action="Edit"/>
           <mvcSiteMapNode title="View Staff" controller="Staff" action="Details">
               <mvcSiteMapNode >
               ...
           </mvcSiteMapNode>
        </mvcSiteMapNode>

   </mvcSiteMapNode>
</mvcSiteMap>

请注意,您需要确保根节点在每个 XML 文件中都具有相同的键 - 最好的方法是在每个文件中将键显式设置为相同的值。另请注意,使用 XML 不可能将不同文件中的节点附加到比主页节点更深的位置。尽管您可以在额外文件中相互嵌套节点,但它们都必须附加到主页。

但是,如果您使用IDynamicNodeProvider https://github.com/maartenba/MvcSiteMapProvider/wiki/Defining-sitemap-nodes-using-IDynamicNodeProvider, ISiteMapNodeProvider, or [MvcSiteMapNode]属性 https://github.com/maartenba/MvcSiteMapProvider/wiki/Defining-sitemap-nodes-using-.NET-attributes,您可以在任何需要的地方嵌套每个提供者的节点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何构建具有多个子站点地图的站点地图? 的相关文章

  • 处理 LINQ sum 表达式中的 null

    我正在使用 LINQ 查询来查找列的总和 并且在少数情况下该值有可能为空 我现在使用的查询是 int score dbContext domainmaps Where p gt p SchoolId schoolid Sum v gt v
  • 实体框架代码优先 - 在另一个文件中配置

    使用 Fluent API 将表到实体的映射分开的最佳方法是什么 以便它全部位于单独的类中 而不是内联在 OnModelCreating 方法中 我目前在做什么 public class FooContext DbContext prote
  • 浮点提升:stroustrup vs 编译器 - 谁是对的?

    在 Stroustrup 的新书 C 编程语言 第四版 第 10 5 1 节中 他说 在执行算术运算之前 整数提升用于从较短的整数类型创建整数 类似地 浮点提升是用于从浮点数创建双精度数 我用以下代码确认了第一个声明 include
  • 身份未映射异常

    System Security Principal IdentityNotMappedException 无法转换部分或全部身份引用 该错误仅在应用程序注册后出现一次 当 SecurityIdentifier 无法映射时 例如 返回 Ide
  • 组合 Datepicker 和 Timepicker 值 Win 8.1

    我试图同时使用 Datepicker Timepicker 来返回可以存储在数据库中的 DateTime 例如 我想要安排会议的开始日期和结束日期 如果适用 我将如何将这些值组合成 SQL 数据库可以处理的正确格式 任何反馈都会很棒 我让这
  • 控制台应用程序 .net Core 2.0 的配置

    在 net Core 1 中我们可以这样做 IConfiguration config new ConfigurationBuilder AddJsonFile appsettings json true true Build 这样就可以使
  • glDrawElements 只绘制半个四边形

    这是我的功能 void Object draw2 if mIsInitialised return Tell OpenGL about our vertex and normal data glEnableClientState GL VE
  • C#:使用 System.Text 和 System.Text.RegularExpressions 之间的区别

    在 ASP NET C 应用程序中 我注意到为了使用 Regex 和 StringBuilder 我必须将两者都放在 using System Text using System Text RegularExpressions 从简单的角度
  • 当格式字符串包含“{”时,String.Format 异常

    我正在使用 VSTS 2008 C Net 2 0 执行以下语句时 String Format 语句抛出 FormatException 有什么想法是错误的吗 这是获取我正在使用的 template html 的位置 我想在 templat
  • 为什么以下代码不允许我使用 fgets 获取用户输入但可以使用 scanf?

    这是一个更大程序的简短摘录 但该程序的其余部分无关紧要 因为我认为我能够隔离该问题 我怀疑这与我使用 fgets 的方式有关 我读过 最好使用 fgets 而不是 scanf 但我似乎无法让它在这里正常工作 当我使用以下代码时 程序不会给我
  • C++ Primer 5th Edition 错误 bool 值没有指定最小大小?

    bool 的最小大小不应该是 1 个字节吗 这有点学术性的东西 尽管它们会转换为数字 并且 与其他所有事物一样 它们最终将基本上由计算机内存中的数字表示 但布尔值不是数字 你的bool可以取值true 或值false 即使您确实需要至少 1
  • 在可观察项目生成时对其进行处理

    我有一个IObservable它会生成一次性物品 并且在其生命周期内可能会生成无限数量的物品 因此 我想在每次生成新项目时处理最后一个项目 因此Using http reactivex io documentation operators
  • 如何在 C++ 中使用 PI 常数

    我想在一些 C 程序中使用 PI 常数和三角函数 我得到三角函数include
  • 如何使用 Clang 查找内存泄漏

    我在我的机器 ubuntu 中安装了 Clang 以便发现我的 C 代码中的内存泄漏 我编写了一个示例代码来检查它的工作情况 如下所示 File hello c for leak detection include
  • OpenMP C 程序运行速度比顺序代码慢

    我是 OpenMP 的新手 正在尝试并行化 Jarvis 的算法 然而事实证明 与顺序代码相比 并行程序花费的时间要长 2 3 倍 难道问题本身就不能并行化吗 或者我并行化它的方式有问题 这是我针对该问题的 openMP 程序 其中有 2
  • 改进C++逐行读取文件的能力?

    我正在解析大约 500GB 的日志文件 我的 C 版本需要 3 5 分钟 我的 Go 版本需要 1 2 分钟 我正在使用 C 的流来流式传输文件的每一行以进行解析 include
  • SSBO 是更大的 UBO?

    我目前正在 OpenGL 4 3 中使用 UBO 进行渲染 以将所有常量数据存储在 GPU 上 诸如材料描述 矩阵等内容 它可以工作 但是 UBO 的小尺寸 我的实现为 64kB 迫使我多次切换缓冲区 减慢渲染速度 我正在寻找类似的方法来存
  • 从 C# 中的 .NET SecureString 读取单个字符?

    WPF 的PasswordBox 返回一个SecureString 它对窥探者隐藏密码 问题是你最终必须获得密码的值 而我在网上找到的建议都涉及将值复制到字符串中 这会让你回到窥探者的问题 IntPtr bstr Marshal Secur
  • ASP.NET Core:会话 ID 始终变化

    今天启动了一个全新的 ASP NET Core 网站 按照说明添加会话 我们在索引页上打印出会话 ID 它始终是唯一的 我认为这可能是 cookie 合规性 所以我在 Chrome 的高级设置和调试器中删除了所有 cookie 但横幅不会再
  • 在 C# 中读取/写入命令行程序

    我正在尝试与 C 的命令行程序进行对话 它是一个情绪分析器 它的工作原理如下 CMD gt java jar analyser jar gt Starting analyser 这是我想从我的 C 程序插入内容的地方 例如 I love y

随机推荐