My Custom Route is :
routes.MapRoute(
name: "custom",
url: "{controller}/{action}/{category}/{subcategory}/{lowcategory}/{id}/{ignore}",
defaults: new { controller = "Home", action = "Index", category = UrlParameter.Optional, subcategory = UrlParameter.Optional, lowcategory = UrlParameter.Optional, id = UrlParameter.Optional,ignore = "" }
);
Mvc.sitemap
is:
<mvcSiteMapNode title="Home" controller="Home" action="Index" preservedRouteParameters="category,subcategory,lowcategory,id,ignore">
<mvcSiteMapNode title="About" controller="Home" action="About"/>
My Index
function is:
public ActionResult Index(string category, string subcategory, string lowcategory, int? id)
preservedRouteParameters
is not showing node.Why?Url : http://localhost:59328/Home/Index/mobiles
Expected sitemap: Home > mobiles
Url: http://localhost:59328/Home/Index/mobiles/htc
Expected sitemap: Home > mobiles > htc
Url: http://localhost:59328/Home/Index/mobiles/htc/m8
Expected sitemap: Home > mobiles > htc > m8
Url: http://localhost:59328/Home/Index/mobiles/htc/m8/12/title
Expected sitemap: Home > mobiles > htc > m8 > title
(note id is not included in sitemap)
But actual sitemap is always Home
A SiteMap is a hierarchy. The way MvcSiteMapProvider
works is to match the "current" node and then use the hierarchy to build the links back to the home page. It is similar to the Microsoft sitemap provider in ASP.NET.
To get the hierarchy you want, you need to nest the nodes like you would with Windows folders.
<mvcSiteMapNode title="Home" controller="Home" action="Index">
<mvcSiteMapNode title="Category" controller="Home" action="Index" preservedRouteParameters="category" key="category">
<mvcSiteMapNode title="Subcategory" controller="Home" action="Index" preservedRouteParameters="category,subcategory" key="subcategory">
<mvcSiteMapNode title="Lower Category" controller="Home" action="Index" preservedRouteParameters="category,subcategory,lowercategory" key="lowercategory">
<mvcSiteMapNode title="Title" controller="Home" action="Index" preservedRouteParameters="category,subcategory,lowercategory,id,ignore" key="titleid"/>
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMapNode>
<mvcSiteMapNode title="About" controller="Home" action="About"/>
</mvcSiteMapNode>
In addition, it is not possible to use more than one optional segment in a route. You need to build up your routing using required segments.
routes.MapRoute(
name: "ID",
url: "Home/Index/{category}/{subcategory}/{lowercategory}/{id}/{ignore}",
defaults: new { controller = "Home", action = "Index", ignore = UrlParameter.Optional }
);
routes.MapRoute(
name: "LowerCategory",
url: "Home/Index/{category}/{subcategory}/{lowercategory}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Subcategory",
url: "Home/Index/{category}/{subcategory}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Category",
url: "Home/Index/{category}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Finally, when using preservedRouteParameters
you need to do some more legwork for the title to change dynamically depending on URL. There is a SiteMapTitle attribute for this purpose, but its current implementation does not allow setting the title past the current node and parent node. So you will need to do something like this to set the title of each node:
using MvcSiteMapProvider.Web.Mvc;
public class HomeController : Controller
{
public ActionResult Index(
string category,
string subcategory,
string lowercategory,
int id = 0,
string ignore = "")
{
var currentNode = this.GetCurrentSiteMapNode();
if (currentNode != null)
{
switch (currentNode.Key)
{
case "titleid":
currentNode.Title = ignore;
currentNode.ParentNode.Title = lowercategory;
currentNode.ParentNode.ParentNode.Title = subcategory;
currentNode.ParentNode.ParentNode.ParentNode.Title = category;
break;
case "lowercategory":
currentNode.Title = lowercategory;
currentNode.ParentNode.Title = subcategory;
currentNode.ParentNode.ParentNode.Title = category;
break;
case "subcategory":
currentNode.Title = subcategory;
currentNode.ParentNode.Title = category;
break;
case "category":
currentNode.Title = category;
break;
}
}
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
}
Note there is another option than preservedRouteParameters
- you can use a dynamic node provider to add a node for each category, subcategory, lowercategory, etc. (and nest them properly), then each node will have its own title automatically. See How To Make MvcSiteMapProvider Remember a User's Position for an example.