从Paging UserControl生成使用当前路由值和模型状态的ActionLink / RouteLink

时间:2010-03-11 14:23:23

标签: c# asp.net-mvc asp.net-mvc-routing

我正在实现一个网站,其搜索可以通过从两个不同路径访问的Controller方法执行。一个挂起默认路由(使用Post数据或搜索参数的查询字符串值),一个是SEO优化网址,它通过两个路由值获取位置和短语。第二条路线如下:

routes.MapRoute("SEOSearch", "Search/{seoLocation}/{seoSearchString}",
  new { controller = "Search", 
        action = "SEOResults", 
        seoLocation = (string)null, 
        seoSearchString = (string)null });

您可能想知道为什么我有两条不同的路线 - 这是因为搜索提供了许多其他参数,而不仅仅是位置和短语 - 但我希望SEO'd网址将这两个包含在路径中,而不是使用查询字符串

正如我所说,第一条路线是默认的/controller/action/id路线,正确的控制器/动作是“搜索”和“索引”。

最后,两个动作在控制器中执行相同的搜索操作,并且两者都将使用索引视图呈现其结果,因为它们的结果模型是相同的。

在索引视图中,我使用搜索词的局部视图,另一部分用于结果,另一部分用于分页。

我遇到的问题是让分页控件呈现正确的链接,以使用与当前请求相同的URL格式启动当前搜索下一页

我想要什么

因此,假设您已导航到/Search?Location=[location]&Phrase=[phrase],我希望寻呼机生成的第2页链接为/Search?Location=[location]&Phrase=[phrase]&Page=2

但是,如果您使用/Search/[location]/[phrase]启动了搜索,我希望第2页的链接为/Search/[location]/[phrase]?Page=2

我得到了什么

我最接近的是:

<%=  Html.RouteLink("Previous Page", 
       RouteHelpers.Combine(ViewContext.RouteData.Values, 
       new RouteValueDictionary() { { "Page", Model.Results.PageNo + 1}})) %>

其中RouteHelpers.Combine是我编写的扩展,它接受两个对象并将它们合并到一个RouteValueDictionary中。通过将RouteValues作为当前请求,我能够持久保存当前的Controller和Action名称(无需知道它们是什么) - 但是这会错过ModelState中的一些重要信息 - 即提供的任何额外搜索参数 - 即如果当前的Url为/Search/London/Widgets,则会有效,但如果它是/Search/London/Widgets?PageSize=50,则PageSize参数不会持久保存到外发链接中。

更糟糕的是,如果它是非SEO的网址 - 即/Search?Location=London&Phrase=Widgets,则传出的网址只会变为/Search?Page=x

我的搜索参数从请求中读取到模型类型中,然后被提供给主页和寻呼机本身,所以理论上我可以简单地从那里生成它们 - 但我最终得到了所有url中的参数,即使它们是默认值(因此不需要提供) - 所以url看起来很难看。

我如何实现我想要的目标!?我觉得我突然对MVC一无所知!

1 个答案:

答案 0 :(得分:3)

您不必使用RouteHelper来合并路线值。当您使用ActionLink时,这些值会自动与您的匿名对象结合使用。将覆盖所有现有值并添加新值。这个电话会为你做这件事:

RouteValueDictionary values = RouteValuesHelpers.MergeRouteValues(
    actionName,
    controllerName,
    requestContext.RouteData.Values,
    routeValues,
    includeImplicitMvcValues); // true for ActionLink; false for RouteLink

routeValues是来自匿名对象的值。它们合并到requestContext.RouteData.Values

所以你仍然可以使用:

Html.ActionLink(
    "whatever",
    this.ViewContext.RouteData.Values["action"],
    this.ViewContext.RouteData.Values["controller"],
    new { Page = /* whatever needs to be */ },
    null)

最后必须为空,因此不会将匿名对象与HTML属性混淆。

但是你确实遇到了路由问题,除非你还在默认路由上设置路由约束以仅使用某些操作,否则你的/Search/SeoLocation/SeoSearchString仍将由默认路由处理,SeoLocation成为你的行动和SeoSearchString id

反正。如果您的代码是正确的,那么所有这些值都应该在您的路由值字典中,并按预期传播到您的链接。