代码之家  ›  专栏  ›  技术社区  ›  Andras Zoltan

从使用当前RouteValue和ModelState的分页用户控件生成ActionLink/RouteLink

  •  3
  • Andras Zoltan  · 技术社区  · 15 年前

    我正在实现一个站点,它有一个可以通过控制器方法执行的搜索,控制器方法可以从两个不同的路径访问。一个挂起默认路由(使用post数据或查询字符串值作为搜索参数),一个是seo优化url,它通过两个路由值获取位置和短语。第二条路线是这样的:

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

    你可能想知道为什么我有两个不同的路径-这是因为搜索提供了许多其他参数,而不仅仅是位置和短语-但我希望搜索引擎优化的网址包括这两个在路径中,而不是使用查询字符串。

    正如我所说,第一条路线是默认的 /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中。通过获取当前请求的routeValue,我能够持久化当前控制器和操作名称(而不必知道它们是什么),但是这会忽略来自modelstate的一些重要信息,即提供的任何额外搜索参数,即,如果当前请求网址是 /Search/London/Widgets ,但如果是 /Search/London/Widgets?PageSize=50 然后 PageSize 参数未持久化到传出链接中。

    更糟糕的是,如果它是一个非搜索引擎优化的网址-即。 /Search?Location=London&Phrase=Widgets ,传出的url就变成 /Search?Page=x .

    我的搜索参数是从请求中读取到一个模型类型中的,然后这个模型类型被同时发送到宿主页面和寻呼机本身,所以理论上我可以直接从中生成它们-但是我最终得到的是url中的所有参数,即使它们是默认值(因此它们不是需要提供)-所以url看起来很难看。

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

    1 回复  |  直到 15 年前
        1
  •  3
  •   Robert Koritnik    15 年前

    你不必用你的 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)
    

    结尾处的null是必需的,因此它不会将匿名对象与html属性混淆。

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

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