如何使用多个子Sitemap构建Sitemap? [英] How to structure sitemap with multiple sub sitemap?

查看:82
本文介绍了如何使用多个子Sitemap构建Sitemap?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 MVC4,MvcSiteMapProvider v3.2.1(需要升级到v4).

I am using MVC4, MvcSiteMapProvider v3.2.1 (able to upgrade to v4 is needed).

我的问题是应用程序很大.我想对应用程序进行模块化,并使模块可插拔.
由于站点地图已经很大,因此我想使站点地图也可插拔.
在应用程序启动时,是否可以通过根站点地图从多个xml文件中加载节点来构建站点地图?

My problem is the application is huge. And I want to modularize the application and make the module pluggable.
Since the sitemap is already huge, I want to make the sitemap also pluggalbe.
Is there a way to structure the sitemap with a root sitemap loading nodes from multiple xml files when the application start?

下面是要说明的示例:
原始站点地图:

Here is the example to explain:
The original 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-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>

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

And I want to split the sitemap to be:
Root sitemap:

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

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

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

StaffSiteMap:

StaffSiteMap:

<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>

ClientSiteMap:

ClientSiteMap:

<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".

Your approach is likely causing you to create more nodes than you need. Unless it is important to index your CRUD operations in search engines, there is a shortcut. You can use a single set of nodes for "Index", "Create", "Edit", "Delete", "Details" and use preservedRouteParameters to force them to match every possible "id".

首先,您需要正确嵌套节点,以便它们在每种情况下都能显示正确的痕迹.

First of all, you need to nest the nodes properly so they will show the correct breadcrumb trail in each case.

<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,以确保每个节点始终打开或关闭,而不是在其父节点不可见时不可见.

None of the "Edit", "Delete", and "Details" nodes will be in the menu or other controls, so you will need to use FilteredSiteMapNodeVisibilityProvider to make them invisible in that case. You can set the default visibility provider to FilteredSiteMapNodeVisibilityProvider in the configuration so you don't have to set it on every node. You should also set the VisibilityAffectsDescendants property to false to ensure each node will always toggle on and off instead of being invisible when its parent node is invisible.

内部DI(web.config):

Internal DI (web.config):

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

外部DI(在DI模块中,显示了StructureMap示例):

External DI (in DI module, StructureMap sample shown):

bool visibilityAffectsDescendants = false;

// Module code omitted here...

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

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

To finish up the visibility, you need to set the visibility attribute of each node.

<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来完成此操作.

Also, you will likely want to set the title of the "Index" node so it will show the title of the current record. You can do that with the SiteMapTitleAttribute in each of your action methods.

[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"的字段.您还需要在edit和delete方法(get和post)中进行设置.但是,您还需要确保将属性目标设置为ParentNode,以便它将覆盖详细信息"节点的标题.

This assumes there is a field named "Name" in your Staff table. You will also need to set this in the edit and delete methods (both get and post). But you also need to make sure you set the attribute target to ParentNode so it will override the title of the "Details" node.

[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();
    }
}

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

The result is that you will have fake breadcrumbs that change depending on which record is selected.

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

有关可下载的工作演示,请参阅

For a downloadable working demo, see the Forcing-A-Match project in the code download of How to Make MvcSiteMapProvider Remember a User's Position.

请注意,也可以在MvcSiteMapProvider版本3.x中执行此操作,您只需要在siteMap/providers/add标记中设置默认的可见性提供程序,而忽略关于VisibilityAffectsDescendants的部分.

Note that it is also possible to do this in MvcSiteMapProvider version 3.x, you just need to set the default visibility provider in the siteMap/providers/add tag and ignore the part about 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,并且在同一SiteMap中多次重复XmlSiteMapNodeProvider,则在版本4.x中可能会在配置中使用多个XML文件.这是使用StructureMap的方法.

If you still think it is necessary to organize your SiteMap into smaller files, it is not possible in version 3.x. It is possible in version 4.x to use multiple XML files in your configuration if you use external DI and repeat the XmlSiteMapNodeProvider multiple times for the same SiteMap. Here is how you would do that using 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.sitemapClient.sitemap文件的节点嵌套在Root.sitemap主页下的作用相同.

Note that each XML file will still need a root node, but it will not be parsed into the SiteMap if the includeRootNode argument is false. Effectively this is the same as nesting the nodes of the Staff.sitemap and Client.sitemap files below the home page of Root.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>

Staff.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">

        <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不可能将节点附加到比首页节点更深的其他文件中.尽管您可以在其他文件中相互嵌套节点,但它们都必须附加到主页上.

Note that you need to ensure the root node has the same key in every XML file - the best way to do that is to set the key explicitly to the same value in each file. Also note that with XML it is not possible to attach the nodes in different files any deeper than the home page node. Although you can nest nodes within each other within the extra files, they all must attach to the home page.

但是,如果您使用 IDynamicNodeProvider ISiteMapNodeProvider [MvcSiteMapNode]属性,您可以在需要的任何位置嵌套每个提供程序的节点.

However, if you use IDynamicNodeProvider, ISiteMapNodeProvider, or [MvcSiteMapNode] attribute, you can nest the nodes of each provider wherever you need to.

这篇关于如何使用多个子Sitemap构建Sitemap?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆