I am using MVC4, MvcSiteMapProvider v3.2.1 (able to upgrade to v4 is needed).
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:
<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:
<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>
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.
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 toFilteredSiteMapNodeVisibilityProvider
in the configuration so you don't have to set it on every node. You should also set theVisibilityAffectsDescendants
property to false to ensure each node will always toggle on and off instead of being invisible when its parent node is invisible.Internal DI (web.config):
External DI (in DI module, StructureMap sample shown):
To finish up the visibility, you need to set the
visibility
attribute of each node.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.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.The result is that you will have fake breadcrumbs that change depending on which record is selected.
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.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 aboutVisibilityAffectsDescendants
.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.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
andClient.sitemap
files below the home page ofRoot.sitemap
.Root.sitemap
Staff.sitemap
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.
However, if you use
IDynamicNodeProvider
,ISiteMapNodeProvider
, or[MvcSiteMapNode]
attribute, you can nest the nodes of each provider wherever you need to.