I can't explain (or reproduce) the behavior you are seeing with the trailing slash, but I do see a potential issue.
The following 2 nodes are ambiguous when it comes to matching the node against the incoming route:
<mvcSiteMapNode title="Manage Users" controller="User" action="ManageUsers">
<mvcSiteMapNode title="Users" controller="User" action="ManageUsers" preservedRouteParameters="id">
In both cases, they will match on a URL /User/ManageUsers
. This is because preservedRouteParameters only functions when there is a parameter to preserve, so it acts like an optional value.
The simplest way to fix this is to rename one of the action methods. Typically, these are 2 different pieces of functionality (named Index
and Details
) and applying separation of concerns by putting them into different action methods is a good thing.
Alternatively, you could define a separate route for the first node and then call out that route explicitly.
routes.MapRoute(
name: "User_MangageUsers",
url: "User/ManageUsers",
defaults: new { controller = "User", action = "ManageUsers" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
And your nodes:
<mvcSiteMapNode title="Manage Users" controller="User" action="ManageUsers" route="User_MangageUsers">
<mvcSiteMapNode title="Users" controller="User" action="ManageUsers" preservedRouteParameters="id">
That really doesn't address the problem with the page
parameter. But you shouldn't have one because query string values are ignored by default. I suspect there is a problem with your routing configuration, but since you didn't post it I can't tell you exactly what it is.
In v4.6.10 there was a feature added that allows you to use query string paramters as part of the route matching, and there was an enhancement to make the query string keys case-insensitive in v4.6.18.
If you are using a lower version than v4.6.10, you should upgrade. If you are using at least v4.6.10 you might be able to fix this by adding the page
parameter as a preserved route parameter.
<mvcSiteMapNode title="Manage Users" controller="User" action="ManageUsers" route="User_MangageUsers" preservedRouteParameters="page">
<mvcSiteMapNode title="Users" controller="User" action="ManageUsers" preservedRouteParameters="id">
Update Based on Your Routes
I am still unable to reproduce the problem.
However, you do have a problem with your route configuration - namely, it is not valid to specify 2 optional parameters on a single route. This might have something to do with your trailing slash issue because when you leave both optional parameters off, the result will include an extra trailing slash when the URL is generated. With your current route configuration, the Default
route is an unreachable execution path.
You can fix this by changing your routing around.
routes.MapRoute(
name: "DefaultwithType",
url: "{controller}/{action}/{id}/{type}",
defaults: new { type = UrlParameter.Optional });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" });
Now:
/User/ManageUsers/1/SomeType - matches DefaultwithType
/User/ManageUsers/1 - matches DefaultwithType
/User/ManageUsers - matches Default
/User - matches Default (with action "Index")
/ - matches Default (with controller "Home", action "Index")
With this routing configuration, you can remove the ambiguity between the nodes by specifying the routes explicitly. This may or may not be necessary - try fixing your nodes first, and then this.
<mvcSiteMapNode title="Manage Users" controller="User" action="ManageUsers" route="Default">
<mvcSiteMapNode title="Users" controller="User" action="ManageUsers" route="DefaultwithType" preservedRouteParameters="id">
Update to make Grid work on "Users" Node
// Route to force match with "Users" node
routes.MapRoute(
name: "User",
url: "User/ManageUsers/{id}",
defaults: new { controller = "User", action = "ManageUsers" });
routes.MapRoute(
name: "DefaultwithType",
url: "{controller}/{action}/{id}/{type}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
Nodes:
<mvcSiteMapNode title="Manage Users" controller="User" action="ManageUsers" route="Default">
<mvcSiteMapNode title="Users" controller="User" action="ManageUsers" route="User" preservedRouteParameters="id,page">
Now the User
route will take precedence over the Default
route. The DefaultwithType
route won't match unless a 4 segment URL is supplied - you may need some fixed segments or constraints if you have URLs in your application that are 4 segments that you don't intend to call the last segment {type}
.
I have also included the "page" in preservedRouteParameters. This probably isn't necessary, but if it is included it should match whether or not the page number is in the request.
"MvcSiteMapProvider_AttributesToIgnore" is for making custom attributes on the node that are not included in the route match. It has nothing to do with ignoring values in the incoming URL.