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

Breadcrumbs #212

Closed
cicciopage opened this issue Aug 22, 2013 · 13 comments
Closed

Breadcrumbs #212

cicciopage opened this issue Aug 22, 2013 · 13 comments

Comments

@cicciopage
Copy link

Sometimes the bredcrumbs is not shown. In that case if I open and save again the mvc.sitemap and relaunch the website the breadcrumbs is shown.
It seems a random problem.
Any suggestions?
Thanks,
Francesco.

@NightOwl888
Copy link
Collaborator

If you are using v4, this would be the first complaint we have had about such an issue. Please post your routes, Mvc.sitemap XML, and MvcSiteMapProvider settings from the web.config so we can get some idea how it is configured.

If you are still using v3, this has been reported several times already and is due to the old caching model, which has now been replaced. Upgrading to v4 will probably fix it.

@cicciopage
Copy link
Author

We're using v4. Here the requested files:

Routes:

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Sitemap",
            url: "sitemap.xml",
            defaults: new
            {
                controller = "XmlSiteMap",
                action = "Index",
                page = 0
            }
        );

        routes.MapRoute(
            name: "VarieDefault",
            url: "Varie/{action}",
            defaults: new
            {
                controller = "Varie",
                action = "PaginaNonTrovata"
            }
        );

        routes.MapRoute(
            name: "Notifica",
            url: "Notifica/{action}",
            defaults: new
            {
                controller = "Notifica",
                action = "Index"
            }
        );

        routes.MapRoute(
            name: "Lingua",
            url: "Lingua/{action}",
            defaults: new
            {
                controller = "Lingua",
                action = "Index"
            }
        );

        routes.MapRoute(
            name: "Download",
            url: "Documento/Download/{id}/{nomefile}",
            defaults: new
            {
                controller = "Documento",
                action = "Download",
                id = UrlParameter.Optional,
                nomefile = UrlParameter.Optional
            }
        );

        routes.MapRoute(
            name: "Pagine",
            url: "Home/pagina/{pagina}",
            defaults: new
            {
                controller = "Home",
                action = "Pagina",
                pagina = UrlParameter.Optional
            }
        );

        routes.MapRoute(
            name: "HomeDefault",
            url: "Home/{action}",
            defaults: new
            {
                controller = "Home",
                action = "Index",
            }
        );

        routes.MapRoute(
            name: "ContenutoDefault",
            url: "Contenuto/{action}/{id}",
            defaults: new
            {
                controller = "Contenuto",
                action = "Index",
                id = UrlParameter.Optional
            }
        );

        routes.MapRoute(
            name: "AmministrazioneDefault",
            url: "Amministrazione/{action}/{id}",
            defaults: new
            {
                controller = "Amministrazione",
                action = "Index",
                id = UrlParameter.Optional
            }
        );

        routes.MapRoute(
            name: "UtenteDefault",
            url: "Utente/{action}/{id}",
            defaults: new
            {
                controller = "Utente",
                action = "Index",
                id = UrlParameter.Optional
            }
        );

        routes.MapRoute(
            name: "AccountDefault",
            url: "Account/{action}/{id}",
            defaults: new
            {
                controller = "Account",
                action = "Index",
                id = UrlParameter.Optional
            }
        );

        routes.MapRoute(
            name: "ProgettoBase",
            url: "Progetto/{action}/{id}",
            defaults: new
            {
                controller = "Progetto",
                action = "Index",
                id = UrlParameter.Optional
            }
        );

        routes.MapRoute(
            name: "RouteSendAvvisoUtenteNonRegistrato",
            url: "Attivita/SendAvvisoUtenteNonRegistrato/{emailUtente}",
            defaults: new
            {
                controller = "Attivita",
                action = "SendAvvisoUtenteNonRegistrato",
                emailUtente = UrlParameter.Optional
            }
        );


        routes.MapRoute(
            name: "DefaultProgetto",
            url: "{idProgetto}/{controller}/{action}/{id}",
            defaults: new
            {
                controller = "Home",
                action = "Index",
                id = UrlParameter.Optional
            }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new
            {
                controller = "Home",
                action = "Index",
                id = UrlParameter.Optional
            }
        );

Mvc.sitemap XML:

<mvcSiteMapNode title="Pagina" dynamicNodeProvider="WebCondominio.Controllers.WebCondominioPublicDynamicNodeProvider, WebCondominio"/>

<mvcSiteMapNode title="$resources:Mvc.sitemap,ProgettiTitle" controller="Progetto" action="Index" roles="Utente, Membro, Coordinatore, Gestore progetti, Amministratore" key="Progetti" resourceKey="Progetti">

  <mvcSiteMapNode title="$resources:Mvc.sitemap,DatiProgettoTitle" controller="Progetto" action="View" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Progetti_View" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id"/>
  <mvcSiteMapNode title="$resources:Mvc.sitemap,EditTitle" controller="Progetto" action="Edit" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Progetti_Edit" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id"/>
  <mvcSiteMapNode title="$resources:Mvc.sitemap,ConsegnaProgettoTitle" controller="Progetto" action="Consegna" roles="Coordinatore, Gestore progetti, Amministratore" key="Progetti_Consegna" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id"/>
  <mvcSiteMapNode title="$resources:Mvc.sitemap,CreateTitle" controller="Progetto" action="Create" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Progetti_Create" visibility="SiteMapPathHelper,!*"/>
  <mvcSiteMapNode title="$resources:Mvc.sitemap,DeleteTitle" controller="Progetto" action="Delete" roles="Coordinatore, Gestore progetti, Amministratore" key="Progetti_Delete" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id"/>

  <mvcSiteMapNode title="$resources:Mvc.sitemap,MembriTitle" controller="Membro" action="Index" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Membri" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id, idProgetto">
    <mvcSiteMapNode title="$resources:Mvc.sitemap,ViewTitle" controller="Membro" action="View" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Membri_View" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id, idProgetto"/>
  </mvcSiteMapNode>

  <mvcSiteMapNode title="$resources:Mvc.sitemap,AttivitaTitle" controller="Attivita" action="Index" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Attivita" visibility="SiteMapPathHelper,!*" preservedRouteParameters="idProgetto">
    <mvcSiteMapNode title="$resources:Mvc.sitemap,CreateTitle" controller="Attivita" action="Create" roles="Coordinatore, Gestore progetti, Amministratore" key="Attivita_Create" visibility="SiteMapPathHelper,!*" preservedRouteParameters="idProgetto"/>
    <mvcSiteMapNode title="$resources:Mvc.sitemap,EditTitle" controller="Attivita" action="Edit" roles="Coordinatore, Gestore progetti, Amministratore" key="Attivita_Edit" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id, idProgetto"/>
    <mvcSiteMapNode title="$resources:Mvc.sitemap,ViewTitle" controller="Attivita" action="View" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Attivita_View" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id, idProgetto"/>
  </mvcSiteMapNode>     

  <mvcSiteMapNode title="$resources:Mvc.sitemap,GruppiTitle" controller="Gruppo" action="Index" roles="Coordinatore, Gestore progetti, Amministratore" key="Gruppi" visibility="SiteMapPathHelper,!*" preservedRouteParameters="idProgetto">
    <mvcSiteMapNode title="$resources:Mvc.sitemap,CreateTitle" controller="Gruppo" action="Create" roles="Coordinatore, Gestore progetti, Amministratore" key="Gruppi_Create" visibility="SiteMapPathHelper,!*" preservedRouteParameters="idProgetto"/>
    <mvcSiteMapNode title="$resources:Mvc.sitemap,EditTitle" controller="Gruppo" action="Edit" roles="Coordinatore, Gestore progetti, Amministratore" key="Gruppi_Edit" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id, idProgetto"/>
  </mvcSiteMapNode>

  <mvcSiteMapNode title="$resources:Mvc.sitemap,DocumentiTitle" controller="Documento" action="Index" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Documenti" visibility="SiteMapPathHelper,!*" preservedRouteParameters="idProgetto">
    <mvcSiteMapNode title="$resources:Mvc.sitemap,CreateTitle" controller="Documento" action="Create" roles="Coordinatore, Gestore progetti, Amministratore" key="Documenti_Create" visibility="SiteMapPathHelper,!*" preservedRouteParameters="idProgetto"/>
    <mvcSiteMapNode title="$resources:Mvc.sitemap,EditTitle" controller="Documento" action="Edit" roles="Coordinatore, Gestore progetti, Amministratore" key="Documenti_Edit" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id, idProgetto"/>
    <mvcSiteMapNode title="$resources:Mvc.sitemap,ViewTitle" controller="Documento" action="View" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Documenti_View" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id, idProgetto"/>
  </mvcSiteMapNode>

  <mvcSiteMapNode title="$resources:Mvc.sitemap,ComunicazioniTitle" controller="Comunicazione" action="Index" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Comunicazioni" visibility="SiteMapPathHelper,!*" preservedRouteParameters="idProgetto">
    <mvcSiteMapNode title="$resources:Mvc.sitemap,CreateTitle" controller="Comunicazione" action="Create" roles="Coordinatore, Gestore progetti, Amministratore" key="Comunicazioni_Create" visibility="SiteMapPathHelper,!*" preservedRouteParameters="idProgetto"/>
    <mvcSiteMapNode title="$resources:Mvc.sitemap,ViewTitle" controller="Comunicazione" action="View" roles="Membro, Coordinatore, Gestore progetti, Amministratore" key="Comunicazioni_View" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id, idProgetto"/>
  </mvcSiteMapNode>

</mvcSiteMapNode>

<mvcSiteMapNode title="$resources:Mvc.sitemap,ContenutiTitle" controller="Contenuto" action="Index" roles="Gestore dei contenuti, Amministratore" key="Contenuti" resourceKey="Contenuti">
  <mvcSiteMapNode title="$resources:Mvc.sitemap,CreateTitle" controller="Contenuto" action="Create" roles="Gestore dei contenuti, Amministratore" key="Contenuti_Create" visibility="SiteMapPathHelper,!*"/>
  <mvcSiteMapNode title="$resources:Mvc.sitemap,EditTitle" controller="Contenuto" action="Edit" roles="Gestore dei contenuti, Amministratore" key="Contenuti_Edit" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id"/>
</mvcSiteMapNode>

<mvcSiteMapNode title="$resources:Mvc.sitemap,AmministrazioneTitle" controller="Amministrazione" action="Index" roles="Amministratore" key="Amministrazione" resourceKey="Amministrazione"/>

<mvcSiteMapNode title="$resources:Mvc.sitemap,UtentiTitle" controller="Utente" action="Index" roles="Amministratore" key="Utenti">
  <mvcSiteMapNode title="$resources:Mvc.sitemap,CreateTitle" controller="Utente" action="Create" roles="Amministratore" key="Utenti_Create" clickable="false" visibility="SiteMapPathHelper,!*"/>
  <mvcSiteMapNode title="$resources:Mvc.sitemap,EditTitle" controller="Utente" action="Edit" roles="Amministratore" key="Utenti_Edit" clickable="false" visibility="SiteMapPathHelper,!*" preservedRouteParameters="id"/>
</mvcSiteMapNode>

<mvcSiteMapNode title="$resources:Mvc.sitemap,MieiDatiTitle" controller="Account" action="EditAccount" roles="Amministratore" key="Account_Edit" visibility="SiteMapPathHelper,!*"/>
<mvcSiteMapNode title="$resources:Mvc.sitemap,EditEmailTitle" controller="Account" action="EditEmail" roles="Amministratore" key="Account_EditEmail" visibility="SiteMapPathHelper,!*"/>
<mvcSiteMapNode title="$resources:Mvc.sitemap,EditPasswordTitle" controller="Account" action="EditPassword" roles="Amministratore" key="Account_EditPassword" visibility="SiteMapPathHelper,!*"/>
<mvcSiteMapNode title="$resources:Mvc.sitemap,DeleteAccountTitle" controller="Account" action="DeleteAccount" roles="Amministratore" key="Account_DeleteAccount" visibility="SiteMapPathHelper,!*"/>

MvcSiteMapProvider settings:

@NightOwl888
Copy link
Collaborator

Nothing stands out as being configured wrong in your settings.

The current node will be null in the case where you navigate to a page and no match is found in your sitemap. This will cause the SiteMapPath to disappear. If this is the case, it definitely won't be random - it will always happen when you navigate to that URL, and navigating to a URL that causes a match will cause it to reappear. Could you check whether that is the case?

I take it you have upgraded from v3 based on your advanced configuration. There is a bug that was fixed that will cause MvcSiteMapProvider to behave differently than its predecessor. The preserved route parameters used to be written to the shared cache. This caused MvcSiteMapProvider to remember the parameter value across requests, but also meant that if another user requested the value it would be overwritten by the new user. This has been fixed - the value is written to the request cache, but also means that these preserved route parameters are not remembered on subsequent requests.

Have a look at #207 for an example of how to fix this.

@cicciopage
Copy link
Author

Thanks for your suggestions but we checked and it's not that case.
We'are doing some tests and the same breadcrumbs (same action) appears and not in the same navigation session. We tried to navigate back and forth between action of the same controller and the breadcrumbs sometime appears and sometimes not. It seems to be a cache error. We set 1 minute cache. (). Could it be?

@cicciopage
Copy link
Author

We changed a xml row
from
preservedRouteParameters="id, idProgetto"

to
preservedRouteParameters="idProgetto"

We removed the ID from the preservedRouteParameters because it's not used by the action and now after 10 minutes the breadcrumbs never diseappears. Could it be that the problem?

@NightOwl888
Copy link
Collaborator

That could cause the problem if you also have an "id" in the current request that doesn't really belong in the node to produce the match. PreservedRouteParameters will always copy all of the values in the list from the current request if they exist. And if the extra parameter causes the match not to occur, it will cause the current node to be null and the breadcrumb to disappear.

It also could explain why it is intermittent, as you might be getting some URLs built with an "id" and some without, and are getting a cascading effect when switching back and forth.

I think that rather than theorizing about the issue, you should setup debugging of MvcSiteMapProvider so you can step through the code and analyze what is happening. The best place to start would be the MatchesRoute method to see what is in the RouteValues dictionary and what is in the passed in route values of the current request when the match doesn't occur on the node that should be the current node.

Or, if you could build a small demo project that reproduces the issue and either post it on GitHub or zip it and make it available for download, I could take a look. Please provide instructions what I need to do to make the problem appear if you go this route.

@cicciopage
Copy link
Author

I'll try to setup debugging in the next days... at moment it seems to work great! :) thanks for helping!

@NightOwl888
Copy link
Collaborator

Alright. I suspect the difference you were seeing is due to the fact that it no longer persists route values across requests - that explains why the behavior changed for the better when you removed the "id".

But since we had at least 3 other complaints of configurations like this not working correctly, I have added a session caching option for RouteValues. According to Maarten, the persistent caching of the RouteValues was an unintended side effect of the preservedRouteParameters and SiteMapPreserveRouteDataAttribute features, so the default will be to use the request cache. That is, session caching will be disabled by default.

The session caching will depend on ASP.NET session state by default but you will be able to create a small custom class to return a user id string that is stored in a cookie or other location if preferred (similar to ITempDataProvider).

@danielpalme
Copy link
Contributor

I have a similar problem. To reproduce please follow these steps:

  1. Create new MVC4 project (Internet Application)
  2. Install SitemapProvider
  3. Add @Html.MvcSiteMap().SiteMapPath() to "Layout.cshtml"
  4. Add the following model class:
namespace MvcApplication1.Models
{
    public class About
    {
        public string Header { get; set; }
    }
}
  1. Update the About method of the HomeController:
[SiteMapTitle("Header")]
public ActionResult About()
{
    var model = new About()
    {
        Header = Guid.NewGuid().ToString()
    };

    return View(model);
}

Now if you hit /Home/About some random GUID is shown in the breadcrumb. That's OK.
Now hit /Home/About/1: No breadcrumb visible

If you restart IIS (Express), and hit /Home/About/1 a GUID is shown, but if you hit /Home/About/2 or /Home/About breadcrumb does not exist.

Seems to be some caching issue. Any idea how to resolve this problem?

@NightOwl888
Copy link
Collaborator

You are not getting a match on /Home/About/1 the first time because you do not have an action parameter on your About method and you made no mention of putting the preservedRouteParameters="id" into your configuration.

In your sitemap you have:

Name Value
controller Home
action About

And in your route you have:

Name Value
controller Home
action About
id 1

This is not a match. To make it match you need to have an id in the sitemap side, which can be done by making a node that includes it or by using preservedRouteParameters to force every id to match a single node (it actually copies the value from the route of the current request). Please review Routing Basics.

The second case I have confirmed is a bug - the preserved route parameters are not being ignored when the sitemap is being built, therefore the values are being added to the permanent cache rather than the request cache.

This may be related to the behavior that @cicciopage was seeing. Thanks for giving me a reliable way to reproduce the behavior. I will be rolling this into a patch that will be released within a few hours.

NightOwl888 added a commit that referenced this issue Aug 28, 2013
…tten to shared cache. Also fixes recursion issue where route values are being copied from the current request multiple times.
@NightOwl888
Copy link
Collaborator

Ok, the fix is now live in v4.0.17. Versioning is still messed up, though - I am still working with Maarten on that.

@danielpalme
Copy link
Contributor

Thanks for the quick fix.

@NightOwl888
Copy link
Collaborator

@cicciopage

I suspect your issue was entirely based on the problem I fixed in v4.0.17. For now, I am marking this closed. Feel free to reopen it again if you start seeing similar behavior.

Also, you might want to take a look at How to Make MvcSiteMapProvider Remember a User's Position for a detailed look at how the route matching works.

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