MVC BeginForm - 使用 GET 将参数传递给控制器

MVC BeginForm - passing parameters to controller using GET

我正在对我的应用程序的一个视图实施搜索过滤器。我努力使用 @Html.BeginForm() 和 GET 请求将 routeValues 传递给控制器​​操作。

该操作接受以下属性:

public ActionResult Books(int id, string type, string search)
{
    //rest of the code
}

视图的搜索框如下所示:

@model ILookup<string, CityLibrary.Models.Library.Book>
.... 
@using (Html.BeginForm("Books", "Collections", new { id = Model.First().First().CollectionId, type = ViewBag.BookType }, FormMethod.Get, null))
{
    <div class="input-group col-md-4">
        @Html.TextBox("search", null, new { @class = "form-control form-control-fixed-width", @placeholder = "Filter title..." })
        <span class="input-group-btn">
            <button class="btn btn-default" type="submit">
                <span class="glyphicon glyphicon-search"></span>
            </button>
        </span>
    </div>
}

提交搜索框时出现问题。控制器操作获取 idsearch 字符串,但 type 始终是 null,即使 ViewBag.BookType 不是 null。 Fiddler 显示:

GET /Collections/Books/2?search=searchterm

这似乎完全忽略了请求中的 type 参数。

浏览器中的源代码:

<form action="/Collections/Books/2?type=available" method="get">
    <div class="input-group col-md-4">
        <input class="form-control form-control-fixed-width" id="search" name="search" placeholder="Filter title..." type="text" value="" />
        <span class="input-group-btn">
            <button class="btn btn-default" type="submit">
               <span class="glyphicon glyphicon-search"></span>
            </button>
        </span>
    </div>
</form> 

跟GET方法有关系吗?我想避免发布,因为我必须使用基本相同的代码编写另一个控制器操作。

编辑: 似乎问题发生在我尝试使用 GET 请求时。发布表单实际上将所有参数传递给控制器​​操作。这是为什么?

此行为符合 HTML specifications,特别是对于带有 method="get" 的表格,(我强调)

Mutate action URL

Let destination be a new URL that is equal to the action except that its <query> component is replaced by query (adding a U+003F QUESTION MARK character (?) if appropriate).

因此,表单 action 属性中的查询字符串值将替换为 name/value 对表单控件生成的查询字符串。

解决此问题的两个选项:

  1. BeginForm()方法中移除new { type = ViewBag.BookType }并为参数

    添加隐藏输入
    <input type="hidden" name="type" value="@ViewBag.BookType" />
    
  2. 为该方法创建自定义路由定义,以便将 type 添加为路由参数,而不是查询字符串值(注意这必须在默认路由之前)

    routes.MapRoute(
        name: "Books",
        url: "Collections/Books/{id}/{type}",
        defaults: new { controller = "Collections", action = "Books" }
    );
    

    这样您当前的 BeginForm() 代码将生成

    <form action="/Collections/Books/2/available" method="get">
    

并且表单提交将导致 url 的 Collections/Books/2/available?search=searchterm