MVC 路由 - 存在默认值时不应用查询字符串

MVC routing - Query strings are not applied when default is present

我正在使用这个路由配置:

   routes.MapRoute("Default23",
                "{category}",
                new { controller = "Product", action = "List", page = 1 }
            );

控制器方法如下:

 public ViewResult List(string category, int page = 1)
{
}

但是,如果我使用:

http://localhost:44123/chess?page=2

然后我看到 page=1(不是我预期的 2):

BTw - 如果我将路线更改为:

 routes.MapRoute("Default23",
                "{category}",
                new { controller = "Product", action = "List"  }
            );

然后我确实看到了正确的值:

为什么会这样?如果我不设置值,我只想设置一个默认值 . 为什么设置默认值会阻止读取查询字符串值?

为了解释这种行为,MapRoute 的第三个参数是(我强调的)

An object that contains default route values.

通过指定 new { controller = "Product", action = "List", page = 1 },您正在为 page 定义一个路由值(即使它不是您 url 定义中的一个段)并给它一个默认值 1.

现在,当您导航到 ../chess?page=2 时,它与您的 Default23 路线匹配,并且 'chess' 的值已分配给 {category} 段,但没有分配任何内容page 因为 {page} 没有段(它是一个查询字符串值)。

当执行您的 List(string category, int page = 1) 方法时,DefaultModelBinder 按以下顺序计算绑定值

  1. 之前绑定的动作参数,当动作是子动作时 动作
  2. 表单值
  3. JSON 请求正文(ajax 调用)
  4. 路由数据
  5. 查询字符串参数
  6. 已发布的文件

对于GET,1、2、3、6不适用,所以DefaultModelBinder先求Route数据(RouteData.Values),找到"chess"的值category(来自url)。它还为 page 找到值“1”(因为您在路由定义中为其定义了默认值)。

此时你有 category="chess", page=1.

然后 DefaultModelBinder 计算查询字符串参数 (Request.QueryString) 并找到 page 的值“2”,但是因为 page 已经设置, 它被忽略了。默认情况下,DefaultModelBinder 绑定它找到的第一个匹配项并忽略所有后续匹配项(除非绑定到 IEnumerable 属性)。

所以此时(绑定过程结束)您仍然有 category="chess", page=1