【问题标题】:Generate ActionLink/RouteLink from Paging UserControl that uses the current routevalues and modelstate从使用当前路由值和模型状态的 Paging UserControl 生成 ActionLink/RouteLink
【发布时间】:2010-03-11 14:23:23
【问题描述】:

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

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

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

正如我所说,第一个路由是默认的 /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 的 url - 即/Search?Location=London&amp;Phrase=Widgets,那么传出的 url 就会变成 /Search?Page=x

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

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

【问题讨论】:

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


    【解决方案1】:

    您不必使用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 成为你的操作,@987654328 @id

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

    【讨论】:

    • 我从另一个网络帖子(可能是 Scott Gu)中发现了约束问题,它解决了两条路线混淆的问题。我当前的解决方案并不理想 - 我派生了一个新的 Route Type,它添加了 Route Name(用于将路由添加到 RouteTable - 无法相信您无法恢复路由的原始名称!) - 然后我为“当前页面”创建了一个链接生成扩展方法,该方法将其从当前路由中破解并将其馈送到 RouteLink 重载中。当下一个截止日期过去时,我将调查此解决方案;谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-09
    • 1970-01-01
    • 2010-12-27
    • 2014-10-11
    • 1970-01-01
    相关资源
    最近更新 更多