@ Html.BeginForm()如何工作?

Iva*_*nov 20 asp.net-mvc razor asp.net-mvc-4

我是ASP.NET的新手,刚刚在asp.net上启动了MVC教程.我到了这里http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/examining-the-edit-methods-and-edit-view

到目前为止这么好,问题:

在我的视图中,我有以下代码(使用@model MyFirstMVC4.Models.Movie将模型设置为视图)

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Movie</legend>

        @Html.HiddenFor(model => model.ID)

        //... bla bla html input
        <p>
             <input type="submit" value="Save" />
        </p>
    </fieldset>
}
Run Code Online (Sandbox Code Playgroud)

我的MovieController

    // Shows the view
    public ActionResult Edit(int id = 0)
    {
        Movie movie = db.Movies.Find(id);
        if (movie == null)
        {
            return HttpNotFound();
        }
        return View(movie);
    }

    //
    // POST: /Movie/Edit/5

    [HttpPost] // Handles the view above
    public ActionResult Edit(Movie movie)
    {
        if (ModelState.IsValid)
        {
            db.Entry(movie).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(movie);
    }
Run Code Online (Sandbox Code Playgroud)

这里有一个问题 - 它如何将Movie对象传递给上面的POST方法?!当我观察客户端时

<form action = "/Movie/Edit/1" ... />
Run Code Online (Sandbox Code Playgroud)

在这里我不明白为什么action =同一个视图页面的url?!1同样在服务器端只有Html.BeginForm():(它如何实现发布的操作方法以及要传递的路由参数?它有效,我只是不知道为什么

Vla*_*žić 39

BeginForm代码中没有参数的版本将HTTP POST发送到当前URL,因此如果视图是响应 /Movie/Edit/5,则打开表单标记将如下所示: < form action="/Movie/Edit/5" method="post">

BeginForm HTML帮助器询问路由引擎如何到达MovieController的Edit操作.在幕后,它使用RouteTable公开的Routes属性上名为GetVirtualPath的方法 - 这是您的Web应用程序在global.asax中注册其所有路由的位置.如果您在没有HTML帮助程序的情况下完成所有这些操作,则必须编写以下所有代码:

  @{
 var context = this.ViewContext.RequestContext;
  var values = new RouteValueDictionary{
  { "controller", "movie" }, { "action", "edit" }
 };
  var path = RouteTable.Routes.GetVirtualPath(context, values);
 }
 <form action="@path.VirtualPath" method="get">
  ...
 </form>
Run Code Online (Sandbox Code Playgroud)

你问过电影对象是如何传递的.这称为模型绑定.当您使用参数执行操作时,MVC运行时使用模型绑定器来构建参数.您可以在MVC运行时中为不同类型的模型注册多个模型绑定器,但默认情况下的主力将是DefaultModelBinder.

对于Movie对象,默认模型绑定器检查Movie并查找可用于绑定的所有电影属性.按照您之前检查过的命名约定,默认模型绑定器可以自动将请求中的值转换并移动到电影对象中(模型绑定器还可以创建要填充的对象的实例).换句话说,当模型绑定器看到Movie具有Title属性时,它会在请求中查找名为"Title"的值.请注意,模型绑定器看起来"在请求中"而不是"在表单集合中".模型绑定器使用称为值提供程序的组件来搜索请求的不同区域中的值.模型绑定器可以查看路径数据,查询字符串和表单集合,如果您愿意,还可以添加自定义值提供程序.

  • 尝试覆盖`@Html.BeginForm` - 我提供了`Html.BeginForm("Edit", "Movies", FormMethod.Post)`。请注意,我没有提供路线的第三个“id”部分。然而在生成的标记中,它就在那里:“/Movies/Edit/4”。它是如何做到这一点的?如果我提供 `Html.BeginForm("Delete", "Movies", FormMethod.Post)`,生成的 HTML 没有 `id`:`/Movies/Delete`。 (2认同)

Nic*_*cht 9

当您在BeginForm()没有任何参数的情况下调用时,它默认使用用于呈现当前页面的相同控制器/操作.它假设您将在控制器上使用正确的名称执行操作,该操作将接受回发(您执行此操作).它用它RouteValues来做到这一点.

它会自动将每个输入控件(按名称)绑定到接受回发的操作的参数 - 或者在您的情况下,是接受回发的操作的对象参数的属性.