Skip to content
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

Won't differentiate paths based on different attributes #332

Closed
unklegwar opened this issue Jul 3, 2014 · 6 comments
Closed

Won't differentiate paths based on different attributes #332

unklegwar opened this issue Jul 3, 2014 · 6 comments

Comments

@unklegwar
Copy link

See the scenario described here: https://stackoverflow.com/questions/23732793/multiple-path-to-same-razor-view-asp-net-mvc-breadcrum-using-sitemap-provider/23733872#23733872

For which a solution is demonstrated by NightOwl888's demo code from here:
http://www.shiningtreasures.com/post/2013/08/10/mvcsitemapprovider-4-seo-features#canonical-tag (demo code download https://github.com/NightOwl888/MvcSiteMapProvider-SEO-Features-Tutorial/archive/master.zip)

I am having the same problem as asker, in that, with v4.6.6 of MvcSiteMapProvider, the technique described in the referenced post/article does not work, MvcSiteMapProvider can't use the additional route parameter to differentiate the site map node.

e.g. it can't differentiate:
<mvcSiteMapNode title="About" controller="Home" action="About" />
<mvcSiteMapNode title="Another About" controller="Home" action="About" something="1234" />

and always matches the first one regardless of the urls:

http://somesite.com/home/about
http://somesite.com/home/about?something=1234

However, in the referenced sample code, the technique DOES work, but that code is based on v4.0.6. I was able to confirm the different behaviors between versions.

I suspect that the functionality has been broken and this is a bug.

@NightOwl888
Copy link
Collaborator

The reason it seemed to work in prior versions was because it was attempting to match on both route values and URL. This caused some quirky behavior that led to matches in incorrectly configured applications and tended to break when using route values that change per request because it was then comparing a URL that was cached at startup to one that could change dynamically. That bug had been fixed, but it also meant that query string values were no longer being taken into account.

I modified the behavior so now it takes into account query string values with matching keys that are configured in the node. Route values take precedence over query string values in cases where both of them are in the request.

That said, it won't work exactly like it was in the original example. In order for it to compare the "something" parameter, it needs to be added as a key to the route values. Without comparing this extra value, it will always match.

<?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-4.0"
            xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd">

    <mvcSiteMapNode title="Home" controller="Home" action="Index" metaRobotsValues="index follow noodp noydir">
        <!-- Note that you need to configure the "something" parameter for it to be considered in the match here.
            Making it an empty string ensures it only matches when the parameter is not provided in the query string. -->
        <mvcSiteMapNode title="About" controller="Home" action="About" key="About" something=""/>
        <mvcSiteMapNode title="Another About" controller="Home" action="About" something="1234" canonicalKey="About"/>
        <mvcSiteMapNode title="Contact" controller="Home" action="Contact" metaRobotsValues="noindex nofollow"/>
        <mvcSiteMapNode title="Site Map" controller="Home" action="SiteMap"/>
    </mvcSiteMapNode>

</mvcSiteMap>

@unklegwar
Copy link
Author

One quirk with this, and I'm not sure if it's expected.

With the current URL = /Home/About

If I define the sitemap with:

    <mvcSiteMapNode title="About" controller="Home" action="About" key="About"/>
    <mvcSiteMapNode title="Another About" controller="Home" action="About" something="1234" canonicalKey="About"/>

then it works as expected, and matches the first node.

But if I reverse the node entries:

    <mvcSiteMapNode title="Another About" controller="Home" action="About" something="1234" canonicalKey="About"/>
    <mvcSiteMapNode title="About" controller="Home" action="About" key="About"/>

Then the above URL STILL matches the first one, even though the URL does NOT contain "something=1234". I would expect it to skip that and go to the 2nd one which is a "better" match.

@NightOwl888
Copy link
Collaborator

This sounds like a bug. Opening again until I get a chance to look at it.

@Agramon
Copy link

Agramon commented Sep 2, 2014

I believe this issue caused a new bug, adding any custom attribute makes the Html.MvcSiteMap().SiteMap.CurrentNode empty, removing it again sets the CurrentNode again.
Switching back to v4.6.11.

@NightOwl888
Copy link
Collaborator

To add a custom attribute without messing up your routes you must always add the value to AttributesToIgnore in web.config. This is the way it was in all v4 versions.

If I misunderstood and you are in fact trying to add a custom route value (not a custom attribute), this behavior is what changed. Instead of allowing "partial matches" to match and sometimes override complete matches, it makes sense to not allow any match to succeed that doesn't take into account all configured values. The expected behavior is that any route key and value that is configured must match either a route value or a query string value in the incoming request, otherwise you will get a miss and not a hit. If you want a match to always occur on any value for a particular route key (or querystring value), then you need to configure the key in preservedRouteParameters.

The URL resolver automatically adds all configured route information to the URLs that MvcSiteMapProvider generates - in other words, those URLs should always match the node they are configured for. However, if you are creating URLs from Action, ActionLink, RouteLink, or some other source, you need to be sure to always provide the route information in the request so it will match (or alternatively use preservedRouteParameters to effectively ignore those keys when considering the match).

That said, I would be happy to have a look if you are seeing behavior that is not consistent with this, or not expected. Provide a demo, please.

@Agramon
Copy link

Agramon commented Sep 3, 2014

Adding the custom attribute to the AttributesToIgnore solved the issue. But I didn't need to do this in 4.6.11 or earlier versions, hence my remark. If this intended, this issue can stay closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants