I am using MvcSiteMapProvider 4.6.3, MVC 4.
I want to use Html.MvcSiteMap().Menu() to generate the menu.
The problem is I have multiple parameters in the URLs, which is changed based on user and document id.
My Sitemap looks like:
<mvcSiteMapNode title="Home" controller="Home" action="Index">
<mvcSiteMapNode title="Site Map Test" controller="SitemapTest" action="Index" area="" key="sitemaptestnode">
<mvcSiteMapNode title="Sub1" controller="SitemapTest" action="Sub1" area="" />
<mvcSiteMapNode title="Sub2" controller="SitemapTest" action="Sub2" area="" />
</mvcSiteMapNode>
</mvcSiteMapNode>
These actions need different parameters.
public ActionResult Index(string id, string clientId)
{
return View();
}
public ActionResult Sub1(string id, string productId)
{
return View();
}
public ActionResult Sub2(string id, string staffId)
{
return View();
}
I try to use the Html helper to generate the Menu.
@Html.MvcSiteMap().Menu(node, false, false)
So if I am on the Index page. And the Menu should be
SitemapTest/Index/product1?clientId=clientId2
SitemapTest/Index/client1?productId=product2
SitemapTest/Index/client1?staffId=staffId1
These ids are getting from database.
Is there a way to pass the parameter to the Html help to specify which Id to use for each link?
There are 2 ways, and it depends on whether the route values are directly used to identify page, or are some ambient value.
For values that directly identify the page, you should configure the nodes using IDynamicNodeProvider or ISiteMapNodeProvider so they can build new nodes when new records are added to the database.
public class ProductDynamicNodeProvider
: DynamicNodeProviderBase
{
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
// TODO: Replace MyEntities with your entity framework context object
using (var db = new MyEntities())
{
// Create a node for each album
foreach (var album in db.Products)
{
DynamicNode dynamicNode = new DynamicNode();
dynamicNode.Title = product.Name;
dynamicNode.ParentKey = "Products"; // There must be a node in the SiteMap with key set to "Products" for this to work
dynamicNode.PreservedRouteParameters.Add("id"); // Force a match on this parameter always
dynamicNode.RouteValues.Add("productId", product.Id);
yield return dynamicNode;
}
}
}
}
And for dynamic node providers, you need a definition node that will be used as a template when creating the nodes, and it will not actually exist in the SiteMap.
// This node will be added to the SiteMap and serves as the parent node of each product
<mvcSiteMapNode title="All Products" controller="Products" action="Index" area="" key="Products">
// This node will become a template for each product node, but the node itself won't be added to the SiteMap
<mvcSiteMapNode controller="Products" action="Details" area="" dynamicNodeProvider="MyNamespace.ProductDynamicNodeProvider, MyAssemblyName" />
</mvcSiteMapNode>
For ambient values (userId, sessionId, etc.), you can force the SiteMap to always match them by configuring them as preservedRouteParameters.
<mvcSiteMapNode title="Sub2" controller="SitemapTest" action="Sub2" area="" preservedRouteParameters="clientId,productId,staffId,id" />
You can also combine these 2 techniques by forcing a match on certain parameters and providing node instances for combinations of other parameters.
For an in depth look at these options, read How to Make MvcSiteMapProvider Remember a User's Position.