MVC SiteMap - when different nodes point to the same SiteMap.CurrentNode action does not map to the correct route

Setup:

I am using ASP.NET MVC 4, with mvcSiteMapProvider to manage my menus.

I have a custom menu constructor that evaluates whether a node is in the current branch (i.e. if it SiteMap.CurrentNodeis either CurrentNode or CurrentNode is nested in it). The code is below, but essentially checks the URL of each node and compares it with the URL of the current level, through the "family tree" currentnodes.

CurrentBranch is used by my customizable menu designer to add a class that highlights menu items in CurrentBranch.

Problem:

My custom menu is working fine, but I found that it mvcSiteMapProviderapparently doesn't rate url CurrentNodeaccording:

When two nodes point to the same action and differ only in the action parameter, SiteMap.CurrentNode does not seem to use the correct route (it ignores the distinguishing parameter and by default uses the first route that displays the action defined in node).

Example problem:

In the application I have Members.

The member has a field MemberStatusthat can be "Unprocessed", "Active" or "Inactive". To change the MemberStatus element, I have ProcessMemberControllerin an area called Admin. Processing is performed using an action Processon ProcessMemberController.

mvcSiteMap , BOTH Process. - alternate ( ), "" "":

:

    <mvcSiteMapNode title="Process" area="Admin" controller="ProcessMembers" action="Process" alternate="Unprocessed" />
    <mvcSiteMapNode title="Change Status" area="Admin" controller="ProcessMembers" action="Process" alternate="Processed" />

( , , , - ):

context.MapRoute(
                    "Process_New_Members",
                    "Admin/Unprocessed/Process/{MemberId}",
                    new { controller = "ProcessMembers", 
                        action = "Process", 
                        alternate="Unprocessed", 
                        MemberId = UrlParameter.Optional }
                );


context.MapRoute(
                    "Change_Status_Old_Members",
                    "Admin/Members/Status/Change/{MemberId}",
                    new { controller = "ProcessMembers", 
                        action = "Process", 
                        alternate="Processed", 
                        MemberId = UrlParameter.Optional }
                );

:

Html.ActionLink URL:

@Html.ActionLink("Process", MVC.Admin.ProcessMembers.Process(item.MemberId, "Unprocessed")

// Output (alternate="Unprocessed" and item.MemberId = 12):   Admin/Unprocessed/Process/12


@Html.ActionLink("Status", MVC.Admin.ProcessMembers.Process(item.MemberId, "Processed")

// Output (alternate="Processed" and item.MemberId = 23):   Admin/Members/Status/Change/23

, .

:

, , .. /Admin/Members/Status/Change/47, alternate = "Processed" MemberId 47.

CurrentBranch (. ), , SiteMap.CurrentNode :

PreviousSibling: null
Provider: {MvcSiteMapProvider.DefaultSiteMapProvider}
ReadOnly: false
ResourceKey: ""
Roles: Count = 0
RootNode: {Home}
Title: "Process"
Url: "/Admin/Unprocessed/Process/47"

.., url/Admin/Members/Status/Change/47, SiteMap.CurrentNode.Url /Admin/Unprocessed/Process/47. .., alternate .

CurrentBranch:

/// <summary>
        /// ReadOnly. Gets the Branch of the Site Map that holds the SiteMap.CurrentNode
        /// </summary>
        public static List<SiteMapNode> CurrentBranch
        {
            get
            {
                List<SiteMapNode> currentBranch = null;
                if (currentBranch == null)
                {
                    SiteMapNode cn = SiteMap.CurrentNode;
                    SiteMapNode n = cn;
                    List<SiteMapNode> ln = new List<SiteMapNode>();
                    if (cn != null)
                    {
                        while (n != null && n.Url != SiteMap.RootNode.Url)
                        {
                            // I don't need to check for n.ParentNode == null
                            // because cn != null && n != SiteMap.RootNode
                            ln.Add(n);
                            n = n.ParentNode;
                        }
                        // the while loop excludes the root node, so add it here
                        // I could add n, that should now be equal to SiteMap.RootNode, but this is clearer
                        ln.Add(SiteMap.RootNode);

                        // The nodes were added in reverse order, from the CurrentNode up, so reverse them.
                        ln.Reverse();
                    }
                    currentBranch = ln;
                }
                return currentBranch;
            }
        }

:

?

Html.ActionLlink, , SiteMap.CurrentNode, . , SiteMap.CurrentNode .

+6
4

, , . , MVC , .

- . , , , ..

+3

- !!:

:

, , :

!!! !!

EG, , node, , UNIQUE, :

<mvcSiteMapNode title="Edit Staff" area="Admin" controller="EditStaff" route="Admin_AdministratorDetails" action="Start" key="administrators_details" />
<mvcSiteMapNode title="Edit Staff" area="Admin" controller="EditStaff" route="Admin_StaffDetails" action="Start" key="staff_details" />

, . .

.

, , . . (Solicitors) , MVC, , , . (, ) . , , .

Un-DRY. .

(. , ):

, Html.RouteLink, Html.ActionLink , .

, :

<mvcSiteMapNode title="Details Active Solicitor" area="Solicitors" controller="EditSolicitor" action="Start" route="Active_Details" key="company_activeSolicitors_details"/>

RouteLink:

@Html.RouteLink("Details", "Active_Details", new { action="Start", controller="EditSolicitor", idSolicitor = item.SolicitorId, returnUrl = Request.RawUrl })

, :

context.MapRoute(
                "Unprocessed_Details",
                "Unprocessed/Edit/{idSolicitor}/{action}",
                new { action = "Start", controller = "EditSolicitor", idSolicitor = UrlParameter.Optional }
            );

            context.MapRoute(
                "Inactive_Details",
                "Inactive/Edit/{idSolicitor}/{action}",
                new { controller = "EditSolicitor", action = "Start", idSolicitor = UrlParameter.Optional }
            );

            context.MapRoute(
                "Active_Details",
                "Solicitors/Edit/{idSolicitor}/{action}",
                new { controller = "EditSolicitor", action = "Start", idSolicitor = UrlParameter.Optional }
            );

, , . mvcSiteMapNode, , , .

, befuddled XML:

XML, -. , .

, mvcSiteMapNodes befuddlement.

,

, . , , , . , , .

:

, , mvcSiteMapNode.

+2

Just in case, you can try the following:

context.MapRoute(
                    "Process_New_Members",
                    "Admin/{alternate}/Process/{MemberId}",
                    new { controller = "ProcessMembers", 
                        action = "Process", 
                        alternate="Unprocessed", 
                        MemberId = UrlParameter.Optional }
                );

Thus, you will distinguish each route, requiring this additional parameter.

0
source

You can use urlin yours mvcSiteMapNode. as below:

<mvcSiteMapNode title="Process" area="Admin" controller="ProcessMembers" action="Process" aurl="/Admin/ProcessMembers/Process/Unprocessed"/>
<mvcSiteMapNode title="Change Status" area="Admin" controller="ProcessMembers" action="Process" url="/Admin/ProcessMembers/Process/Processed" />

Of course, you must use the appropriate RoutConfigURL to work. There is a sample here .

0
source

All Articles