Friday, October 27, 2017

[MVC] MvcSiteMap with custom route

 MVC    MvcSiteMap    Route

▌Scenario


In the previous article: [MVC] MvcSiteMap with Dependency Injection, we successfully created a menu with MvcSiteMap.





If we define a custom route with extra route placeholders, such as

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

Which {lang} is expected to have these values,

http://localhost:1410/EN/Home/Index
http://localhost:1410/CN/Home/Index
http://localhost:1410/ZH/Home/Index


However, the problem is that we will always get the default value for {lang} in the node’s url like the following picture from MvcSiteMap in default!




What I expect is to have the same {lang} value as the current url.





There are two ways to get this job done, let’s take a look.


▋Related articles





▌Environment


▋Visual Studio 2017
▋Microsoft Sql Server 2012
▋MvcSiteMapProvider.MVC5 4.6.22
▋MvcSiteMapProvider.MVC5.DI.Unity 4.6.22


▌Implement


▋Method 1. Update MenuNodeProvider

While we create every node in MenuNodeProvider, we also give every node a route value for key: "lang"


▋MenuNodeProvider.cs

DynamicNode dynamicNode = new DynamicNode()
{
    //…
};

string lang = string.Empty;

CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
if (ci != null)
{
       switch (ci.Name.ToLower())
       {
          case "en-us":
               lang = "EN";
               break;
          case "zh-cn":
                lang = "CN";
                break;
          default:
                lang = "ZH";
                break;
        }
}
                       
dynamicNode.RouteValues.Add("lang", lang);



So that the route value will be mapped to the url pattern’s placeholders: {lang}


▋Method 2. Update Display template

First go to _Layout.cshtml and find the following codes.

@Html.MvcSiteMap().Menu("BootstrapMenuHelperModel", false)

Open BootstrapMenuHelperModel.cshtml, we will create a @Helper to display the current route value for {lang}.

@helper LangValue()
{
    var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;

    string lang = "Default";
    if (routeValues != null)
    {
        if (routeValues.ContainsKey("lang"))
        {
            lang = routeValues["lang"].ToString();
        }
    }

    @lang;
}


Update the url of link from

<a href="@url">

To

<a href="/@LangValue()@url">


Last, make sure that in the custom route pattern, the placeholder: {lang}, DOES NOT have a default value.
PS. If you set Area for the MVC website, update the Area’s route as well.

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




▌Reference




No comments:

Post a Comment