Search code examples
asp.net-mvcmvcsitemapprovider

Breadcrumb not showing on culture change


Disclaimer : I'm still a rookie, and I'm maintaining a big project made by someone else with little documentation. So I might be missing something obvious.

Here goes : My web application can be accessed by 2 dns names, "www.website.com" and "www.siteweb.com" one in english and the other in french.

There used to be a bilingual splash page that prompts for the language but since we have 2 urls, I had to eliminate the splash page and automatically redirect to the main page in the language that corresponds to the URL that was used to access it.

Here's is the redirection code located on the defunct splash page (index.vbhtml) :

@Code
If Request.ServerVariables("SERVER_NAME").Contains(ConfigurationManager.AppSettings("SiteDNSnameEN")) Then
    Response.Redirect(Url.Action("SetLanguage", Resources.ResourceURL.CONTROLLER_LANGUAGE, New With {.pCulture = "en-CA", .pReturnURL = "/Home"}))
ElseIf Request.ServerVariables("SERVER_NAME").Contains(ConfigurationManager.AppSettings("SiteDNSnameFR")) Then
    Response.Redirect(Url.Action("SetLanguage", Resources.ResourceURL.CONTROLLER_LANGUAGE, New With {.pCulture = "fr-CA", .pReturnURL = "/Accueil"}))
End If 
@EndCode

When on the French "Home" page, the breadcrumb works fine when I use the language toggle button, which refers to a controller that translates the url and triggers "SetLanguage" which basically sets CurrentCulture and CurrentUICulture and reloads the pReturnURL. Everything gets translated properly and there's no problem.

But if I use the English URL (or fake using it, because in dev it's only localhost), the breadcrumb is displayed , but when I press on the language toggle button, the breadcrumb is not being displayed. My best guess is that MVCSiteMapProvider is still looking for the english ressources because the breadcrumb gets displayed on that one page that happens to have the same path in french or english.

I have played around with globac.asax's routes and with the redirecting, but I only achieve to fix one language and screw the other.

I'm sure there is a just a small fix that have been eluding me for quite a while now. Somewhere along the line, the culture change seems to not get done. I've troubleshooted the Action "SetLanguage" and it always shows the expected culture. That might not be it but I'm thinking MVCSiteMapProvider is not always following for some reason.

Here's the part of Global.asax that I've tinkered with :

routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
    routes.MapRoute( _
        "Splash", _
        "", _
        New With {.controller = "Root", .action = "Index"} _
    )

    routes.MapTranslatedRoute( _
        "TranslatedRoute", _
        "{controller}/{action}/{id}", _
        New With {.controller = "Home", .action = "Index", .id = ""}, _
        New With {.controller = translationProvider, .action = translationProvider}, _
        False _
    )

    Dim controllerHomeEN = Resources.ResourceURL.ResourceManager.GetString("CONTROLLER_HOME", New CultureInfo(WebHelper.CONST_CURRENT_CULTURE_EN))
    Dim actionIndexEN = Resources.ResourceURL.ResourceManager.GetString("ACTION_INDEX", New CultureInfo(WebHelper.CONST_CURRENT_CULTURE_EN))


    routes.MapRoute( _
        "Default", _
        "{controller}/{action}/{id}", _
        New With {.controller = controllerHomeEN, .action = actionIndexEN, .id = UrlParameter.Optional} _
    )

Solution

  • Usually, when the breadcrumb disappears it means that you are not accounting for all of the request's route values in the node. For example, if you have a "culture" route value being passed from the route and you don't have it setup in preservedRouteParameters, then the node won't match the request.

    Best guess is that you are doing something with your translationProvider that is causing the node not to match. But since you haven't posted the code, I can only imagine what.

    Note that if you are writing to the SiteMapNode.Title property somewhere you shouldn't be, the value could bleed over to other requests. MvcSiteMapProvider v3.x was not threadsafe, so if one request updated a value in the SiteMap's cached nodes, they would be visible in all of the other requests until the cache expires (or until the next request overwrote it).

    Do note that dynamic node providers are not dynamically called per request. They are for creating cached (shared) nodes that are based on dynamic data. Therefore, you should not put any per-request conditions (such as localization) inside of a dynamic node provider.

    The How to Localize Site-Map Data document on MSDN shows the correct way to configure localization in MvcSiteMapProvider v3.x. Do note that there is an issue with deployment of global resources within MVC when using the default file build settings.

    Also see:

    For MvcSiteMapProvider v4.x, you have other options if you were to upgrade. Also, MvcSiteMapProvider v4.x is threadsafe - if you update a value such as Title within the request, it will apply only to the current request and no other user will see it.