我正在使用ASP.NET MVC 4,使用mvcSiteMapProvider来管理我的菜单。
我有一个自定义菜单构建器,用于评估节点是否在当前分支上(即,SiteMap.CurrentNode
是CurrentNode还是CurrentNode嵌套在其下)。代码包含在下面,但基本上检查每个节点的url并将其与currentnode的url进行比较,直到currentnodes“family tree”。
我的自定义菜单构建器使用CurrentBranch添加一个类,该类突出显示CurrentBranch上的菜单项。
我的自定义菜单工作正常,但我发现mvcSiteMapProvider
似乎无法以一致的方式评估url
的{{1}}:
当两个节点指向同一个操作并且仅通过操作的参数进行区分时,SiteMap.CurrentNode似乎没有使用正确的路径(它忽略了区分参数并默认为第一个映射到节点中定义的操作的路由。
在我有CurrentNode
的应用中。
会员的Members
字段可以是“未处理”,“有效”或“无效”。要更改MemberStatus,我在名为Admin的区域中有一个MemberStatus
。处理是使用ProcessMemberController
上的Process
操作完成的。
我的mvcSiteMap有两个节点,两个节点都映射到ProcessMemberController
动作。它们之间的唯一区别是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" />
Html.ActionLink帮助程序使用路由并生成我期望的URL:
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("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
,对应于alternate =“Processed”和MemberId为47.
调试我的静态CurrentBranch属性(见下文),我发现SiteMap.CurrentNode显示:
/Admin/Members/Status/Change/47
即,对于/ Admin / Members / Status / Change / 47的请求网址,PreviousSibling: null
Provider: {MvcSiteMapProvider.DefaultSiteMapProvider}
ReadOnly: false
ResourceKey: ""
Roles: Count = 0
RootNode: {Home}
Title: "Process"
Url: "/Admin/Unprocessed/Process/47"
评估为SiteMap.CurrentNode.Url
。即,它正在忽略/Admin/Unprocessed/Process/47
参数并使用错误的路径。
alternate
我做错了什么?
路由由Html.ActionLlink按我的预期解释,但不会像我期望的那样被SiteMap.CurrentNode评估。换句话说,在评估我的路由时,SiteMap.CurrentNode会忽略区分备用参数。
答案 0 :(得分:3)
我认为这是因为你试图从参数中获取路线。基本上,MVC只是试图GUESS你可能指的是什么路线。
正确的方法是按名称处理路线。因此,站点地图应引用路由名称而不是控制器,操作等。
答案 1 :(得分:2)
绊脚石:
当使用不同的路由指向同一个控制器操作时,一个节点有不同的节点,我遇到的最大问题是:
你必须给一个关键的不同节点!否则,网站不会出现退货!!
EG,只有路由属性本身是不够的,你必须给每个节点指向相同的动作一个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" />
一旦我意识到这一点,它现在已经开始了。否则,一切都是模糊不清的。
注意:
在问题中,不同路由调用的操作是Process操作。我把它改成了对不同行为的召唤。但是在编辑我的对象(Solicitors)时,我无法做到这一点,因为编辑是由MVC向导完成的,就像我的自定义菜单构建器一样,我编写并且工作得非常好。它只是不可能(或者更确切地说,DRY)三次重建向导。因此,我必须让我的菜单高亮显示正确的工作,不同的路线指向同一个动作。
没有Un-DRY的蠢货。我的客户不值得。
解决方案(请参阅有关操作和路线与问题不同的说明):
Carlos Martinez的建议有效,但您需要使用Html.RouteLink而非Html.ActionLink,以及编辑后的站点地图,详细说明路线。
基本上,在您的节点中,您需要使用route属性:
<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中指定路由名称,就可以在构建菜单时正确区分路由,并且突出显示可以根据需要进行。
关于使用XML困惑的注意事项:
我非常讨厌XML。它让我感到困惑和困惑,尤其是感冒时。
问题是将路由属性添加到mvcSiteMapNodes会增加可能的混乱。
我感到困惑
我最初尝试过卡洛斯的建议,但它没有用。不知道错误是什么,但是用牙齿梳理它并且现在正在工作。令人讨厌的是,我不确定我做错了什么。
生活在希望中
我希望这个文档尽管是mvcSiteMapNode的边缘方面。
答案 2 :(得分:0)
以防万一,您可以尝试以下方法:
context.MapRoute(
"Process_New_Members",
"Admin/{alternate}/Process/{MemberId}",
new { controller = "ProcessMembers",
action = "Process",
alternate="Unprocessed",
MemberId = UrlParameter.Optional }
);
通过这种方式,您可以通过要求此附加参数来区分每条路线。
答案 3 :(得分:0)
您可以在url
中使用mvcSiteMapNode
。如下所示:
<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" />
当然,您应该使用适当的RoutConfig
来使该网址起作用。
有一个示例here。