【问题标题】:How does @Html.BeginForm() works?@Html.BeginForm() 是如何工作的?
【发布时间】:2013-05-20 14:23:02
【问题描述】:

我是 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>
}

我的电影控制器

    // 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);
    }

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

<form action = "/Movie/Edit/1" ... />

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

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-4 razor


    【解决方案1】:

    代码中BeginForm的版本, 不带参数,向当前 URL 发送 HTTP POST,所以如果视图是对 /Movie/Edit/5,开始表单标记将如下所示: &lt; form action="/Movie/Edit/5" method="post"&gt;

    BeginForm HTML 助手询问路由引擎如何到达 电影控制器。在幕后,它在 Routes 上使用名为 GetVirtualPath 的方法 RouteTable 公开的属性——这是您的 Web 应用程序在其中注册其所有路由的地方 全球.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>
    

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

    如果是电影 对象,默认模型绑定器检查电影并找到所有可用的电影属性 用于绑定。按照您之前检查过的命名约定,默认模型绑定器可以自动将请求中的值转换并移动到电影对象中(模型绑定器可以 还创建要填充的对象的实例)。 换句话说,当模型绑定器看到一个 Movie 有一个 Title 属性时,它会寻找一个值 在请求中命名为“标题”。请注意,模型绑定器看起来“在请求中”而不是“在表单中” 收藏。”模型绑定器使用称为值提供者的组件在 请求的不同领域。 模型绑定器可以查看路线数据、查询字符串和表单 集合,您可以根据需要添加自定义值提供者。

    【讨论】:

    • 玩弄 @Html.BeginForm 的覆盖 - 我提供了 Html.BeginForm("Edit", "Movies", FormMethod.Post)。请注意,我没有提供路线的第三个 id 部分。然而在生成的标记中,它就在那里:/Movies/Edit/4。它是如何做到的?如果我提供Html.BeginForm("Delete", "Movies", FormMethod.Post),则生成的HTML 没有id:/Movies/Delete。
    【解决方案2】:

    当您调用 BeginForm() 时不带任何参数,它默认使用与呈现当前页面相同的控制器/动作。它假定您将在控制器上使用正确名称的操作来接受回发(您可以这样做)。它使用RouteValues 来执行此操作。

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

    【讨论】:

      【解决方案3】:

      [HttpPost] 属性赋予您希望在表单的 POST 提交时调用的操作。

      要了解@using (Html.BeginForm()) 的工作原理,您需要知道它已经在哪个页面上。在 2 个不同的视图中使用 @using (Html.BeginForm()) 将返回到两个不同的控制器

      【讨论】:

        【解决方案4】:

        我们可以通过键入简单的 html 或 html 助手来创建表单。 其中之一 Html.BeginForm();这有点奇怪,因为您实际上可以将它包装在 using 语句中,因为这个特定的帮助器返回一个在 C# 中实现 IDisposable 的对象。首先它用开始标签写出来。在底部,当生成的代码对该对象调用 dispose 时,它​​将写出关闭表单标签。所以 BeginForm 给了我一个对象,它会写出我的开始表单标签和我的结束标签。之后,您无需担心任何事情,您只需专注于标签和输入

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-06
          相关资源
          最近更新 更多