-
Notifications
You must be signed in to change notification settings - Fork 218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decorating action with MvcSiteMapNode attributes for multiple parents #369
Comments
Technically it is not possible to have "two parents". The SiteMap is a hierarchical structure, so by definition you can only have 1 parent for a node. Also, 2 nodes with the same URL or route configuration are not supported. If you have 2 nodes configured with the same route information (including preservedRouteParameters), the route matching won't be able to tell them apart, and the first match will always win. This is normal and expected behavior since as I mentioned, it is not supported to have 2 nodes with the same URL. Although you cannot have 2 nodes with the same route configuration, you can create 2 nodes with different route configuration and different URLs that point to the same resource. It looks like you are on the right track, but you didn't provide any way to uniquely identify your invoice list nodes. You must have different URLs for each node. The easiest way to achieve this is to add an additional route parameter, but you could also add another route for the alternate page. You also have incorrectly specified the route parameter for your list nodes as the route for the parent nodes. One way you could solve this is to add another route. [Route(@"billing-information/list/{id:int}/{name:regex([^/]+)}", Name = "InvoiceListForClient")]
// Note this must be different than the above route.
[Route(@"billing-information/serverlist/{id:int}/{name:regex([^/]+)}", Name = "InvoiceListForServer")]
[MvcSiteMapNode(Title = "$resources:Resource,InvoiceListTitle", ParentKey = "DetailsForClient", Key = "ClientInvoiceList", Route = "InvoiceListForClient", PreservedRouteParameters = "id,name")]
[MvcSiteMapNode(Title = "$resources:Resource,InvoiceListTitle", ParentKey = "DetailsForServer", Key = "ServerInvoiceList", Route = "InvoiceListForServer", PreservedRouteParameters = "id,name")] which will give you the URLs
If you want the base URL to be the same for each path, you could also just add a query string parameter to the end by adding a custom attribute (which also goes into route values by default). [Route(@"billing-information/list/{id:int}/{name:regex([^/]+)}", Name = "InvoiceList")]
[MvcSiteMapNode(Title = "$resources:Resource,InvoiceListTitle", ParentKey = "DetailsForClient", Key = "ClientInvoiceList", Route = "InvoiceList", PreservedRouteParameters = "id,name")]
[MvcSiteMapNode(Title = "$resources:Resource,InvoiceListTitle", ParentKey = "DetailsForServer", Key = "ServerInvoiceList", Route = "InvoiceList", PreservedRouteParameters = "id,name", Attributes = @"{ ""server"": 1 }")] which will give you the URLs
The CanonicalKey or CanonicalUrl properties only need apply if your pages are Internet facing and crawled by search engines. This does not change the route configuration in any way, it is just to tell the search engines that you meant to put the same content on 2 different URLs so it doesn't count against you in terms of search engine placement. If that applies to you, you would want to pick one URL as the "master" (or canonical) and make all of the copies point to its key. [Route(@"billing-information/list/{id:int}/{name:regex([^/]+)}", Name = "InvoiceListForClient")]
[Route(@"billing-information/serverlist/{id:int}/{name:regex([^/]+)}", Name = "InvoiceListForServer")]
// This would be your "master" copy of the content (canonical)
[MvcSiteMapNode(Title = "$resources:Resource,InvoiceListTitle", ParentKey = "DetailsForClient", Key = "ClientInvoiceList", Route = "InvoiceListForClient", PreservedRouteParameters = "id,name")]
// And this node is the copy. We need to point it to the master node using the CanonicalKey.
[MvcSiteMapNode(Title = "$resources:Resource,InvoiceListTitle", ParentKey = "DetailsForServer", Key = "ServerInvoiceList", Route = "InvoiceListForServer", PreservedRouteParameters = "id,name", CanonicalKey = "ClientInvoiceList")] You would then use the CanonicalTag HTML helper in the HEAD section of your page and it will automatically generate the tag for you. <head>
@Html.MvcSiteMap().CanonicalTag()
</head> |
Thanks for your detailed answer, it helped me a lot but not your suggested way. Because the real problem caused by could not make work an Action with two route attributes. So i had to split my Detail action into two different parts for server and client. At the end this caused breadcrumb menu problems, because both of these actions has links to the same action. With your answer i tried again to use two route attribute in one Action and able to made it work this time. Thus, there wasn't need to try working MvcSiteMapNode with two parents. Thanks again for this. Still i have some questions, before i create this issue i saw some questions and answers about this. According to them it is possible to use multiple parents at nodes. After your answer, i thought i misunderstood them. You can find links below as mentioned Finally if i am not wrong, there is no bug about canonicalKey like i wrote in my questions.Is it normal that getting an exception about canonicalUrl while using only canonicalKey? |
I have confirmed and patched the issue you reported that an exception is thrown when using MvcSiteMapNodeAttribute is used to configure a CanonicalKey. But I think you are confusing the ability to point 2 nodes to a single piece of content (which is supported) with the ability to have 2 parent nodes (which is not). For example, let's say we have 3 different views (ViewA, ViewB, and ViewC). Let's say you want to structure the SiteMap so ViewC is shown as a child of both ViewA and ViewB. First, lets consider what happens with MVC. When using actions, the views can either be returned via convention, or by explicitly returning them. I have heard (but not confirmed) that it is possible to return the result of one view from another in order to "paint" it with a different route. public class HomeController : Controller
{
public ActionResult ViewA()
{
return View();
}
public ActionResult ViewB()
{
return View();
}
public ActionResult Display()
{
return View("ViewC");
}
public ActionResult Display2()
{
return Display();
}
} In this case, both the URL The same is true if we just return Now that we have the content of ViewC on different URLs, we can take a look at how the content would be configured in a SiteMap. We are not actually configuring any nodes with 2 parents, we are making 2 different navigation paths to the content by mapping each node to a separate route configuration, but making the ViewC node return exactly the same content.
This shows up in the Menu and SiteMap HTML helpers exactly as above. But the SiteMapPath looks as if we are navigating to the same place from multiple parents.
|
Hi all,
In my web application i use Attributed Routes for routing and MvcSiteMapProvider attributes for breadcrumb menu. Everything works fine except one case; pages with multiple parents.
Actually there are some resources about this but none of them worked for me; and also i had noticed something and thought it may be bug so i decided to submit this issue.
First of all i have got to (parent) actions like below
These two actions return views that have link to another action which can be seen below
So i want that breadcrumb menu generated according to referring action.
Here are my few tries
But in my second try, i think i found a bug. After i use CanonicalKey parameter in attribute i got an exception "The 'CanonicalUrl' has already been set. Simultaneous use of both CanonicalUrl and CanonicalKey is not allowed.". However i didn't use CanonicalUrl parameter anywhere in my solution, so i decided to debug with source code. Then i notice exception is thrown by CanonicalUrl set accessor.
Because set value is null but this.canonicalUrl field is empty string ("") and this cause below statement returns true
To solve this problem i changed if statement like below
Anyway this didn't help me to solve and show breadcrumb menu as i want.
I hope you can help me.
The text was updated successfully, but these errors were encountered: