在本节中,您将检查所生成的Edit操作方法和movie
controller的视图。但首先需要采取一个简短的更改,使发布日期看起来更好。打开Models\Movie.cs文件并修改为下面代码:
using System; using System.ComponentModel.DataAnnotations; using System.Data.Entity; namespace MvcMovie.Models { public class Movie { public int ID { get; set; } public string Title { get; set; } [Display(Name = "Release Date")] [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] public DateTime ReleaseDate { get; set; } public string Genre { get; set; } public decimal Price { get; set; } } public class MovieDBContext : DbContext { public DbSet<Movie> Movies { get; set; } } }
你也可以让日期文化像这样:
[Display(Name = "Release Date")] [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)] public DateTime ReleaseDate { get; set; }
我们将在下一个教程介绍DataAnnotations。Display属性指定为一个字段的名称显示(在这种情况下,"Release
Date"而不是"ReleaseDate")。DataType属性指定的数据类型,在这种情况下,这是一个日期,所以字段中存储的时间信息不显示。 DisplayFormat属性属性是在浏览器中的一个错误,使日期格式不正确的需要。
运行应用程序并浏览到电影控制器。将鼠标指针放在一个Edit链接上,查看它链接到的网址。
Edit链接通过在视图的 Html.ActionLink
方法生成Views\Movies\Index.cshtml 视图:
@Html.ActionLink("Edit", "Edit", new { id=item.ID })
HTML对象是一个使用system.web.mvc.webviewpage基类属性的辅助工具。其中的ActionLink方法便于动态生成HTML超链接控制器动作方法链接。ActionLink方法的第一个参数是提供链接文本(例如,<a>编辑我</a>)。第二个参数是调用的动作方法的名称(比如这里的 Edit动作)。最后一个参数是一个匿名对象,生成路由数据(比如这里的身份证号
4)。
在以往的影像显示生成的链接是http://localhost:1234/Movies/Edit/4。默认路由(在App_Start\RouteConfig.cs生成)以URL模式 {controller}/{action}/{id}
。因此,ASP.NET将http://localhost:1234/Movies/Edit/4变成要求Edit动作方法的控制器的参数与电影ID等于4。从App_Start\RouteConfig.cs文件检查下面的代码。MapRoute方法到正确的控制器和动作方法的HTTP请求路由和供应可选的id参数。MapRoute方法也由 HtmlHelpers 使用如连接产生了控制器使用的URL,动作方法和任何路由数据。
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); }
您也可以使用查询字符串传递动作方法参数。例如,URL的http://localhost:1234/Movies/Edit?ID=3也通过了参数标识为3的电影控制器的Edit动作方法。
打开电影控制器。两个Edit操作方法如下所示。
// GET: /Movies/Edit/5 public ActionResult Edit(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } Movie movie = db.Movies.Find(id); if (movie == null) { return HttpNotFound(); } return View(movie); } // POST: /Movies/Edit/5 // To protect from overposting attacks, please enable the specific properties you want to bind to, for // more details see http://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit([Bind(Include="ID,Title,ReleaseDate,Genre,Price")] Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
注意第二个编辑动作方法是之前HttpPost属性。这个属性指定过载的编辑方法只能调用POST请求。你可以应用HttpGet属性于第一个Edit方法,但这不是必要的,因为它是缺省值。(我们会参考操作方法隐式分配HttpGet属性HttpGet方法。)Bind属性是另一个重要的安全机制,防止黑客over-posting数据模型。您应该只包含属性绑定属性,你想改变,你可以读到overposting
overposting安全注意和绑定属性。在本教程中使用的简单的模型,我们将绑定在模型中所有的数据。ValidateAntiForgeryToken属性是用来防止伪造请求和配对与@Html.AntiForgeryToken()在编辑视图文件(Views\Movies\Edit.cshtml),部分如下所示:
@model MvcMovie.Models.Movie @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Movie</h4> <hr /> @Html.ValidationSummary(true) @Html.HiddenFor(model => model.ID) <div class="form-group"> @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> </div>
@Html.AntiForgeryToken()生成一个隐藏表单种防伪标记,必须匹配在电影的Edit方法的控制器。你可以阅读更多关于跨站点请求伪造(也称为XSRF或CSRF)在我的教程XSRF / MVC CSRF预防。
HttpGet编辑方法接受电影ID参数,查找电影使用实体框架发现方法,并返回所选电影编辑视图。如果一部电影不能被发现,HttpNotFound返回。当脚手架系统创建编辑视图时,它检查了电影类和创建代码呈现<标记>和<输入>元素的每个属性类。下面的例子显示了生成的编辑视图的visual studio脚手架系统:
@model MvcMovie.Models.Movie @{ ViewBag.Title = "Edit"; } <h2>Edit</h2> @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Movie</h4> <hr /> @Html.ValidationSummary(true) @Html.HiddenFor(model => model.ID) <div class="form-group"> @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Title) @Html.ValidationMessageFor(model => model.Title) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.ReleaseDate, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.ReleaseDate) @Html.ValidationMessageFor(model => model.ReleaseDate) </div> </div> @*Genre and Price removed for brevity.*@ <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Save" class="btn btn-default" /> </div> </div> </div> } <div> @Html.ActionLink("Back to List", "Index") </div> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
注意,视图模板有一个@ model MvcMovie.Models。电影声明顶部的文件——这指定视图预计模型的视图模板类型的电影。
搭建的代码使用一些辅助方法来简化HTML标记。Html.EditorFor
辅助显示字段的名称(“标题”、“ReleaseDate”,“流派”,或“价格”)。Html。EditorFor助手呈现HTML
<input>元素。Html.ValidationMessageFor
辅助显示任何验证消息相关的财产。
运行应用程序并导航到 /Movies网址。点击一个Edit链接。在浏览器中,视图页面的源代码的HTML表单元素如下所示。
<form action="/movies/Edit/4" method="post"> <input name="__RequestVerificationToken" type="hidden" value="UxY6bkQyJCXO3Kn5AXg-6TXxOj6yVBi9tghHaQ5Lq_qwKvcojNXEEfcbn-FGh_0vuw4tS_BRk7QQQHlJp8AP4_X4orVNoQnp2cd8kXhykS01" /> <fieldset class="form-horizontal"> <legend>Movie</legend> <input data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="4" /> <div class="control-group"> <label class="control-label" for="Title">Title</label> <div class="controls"> <input class="text-box single-line" id="Title" name="Title" type="text" value="GhostBusters" /> <span class="field-validation-valid help-inline" data-valmsg-for="Title" data-valmsg-replace="true"></span> </div> </div> <div class="control-group"> <label class="control-label" for="ReleaseDate">Release Date</label> <div class="controls"> <input class="text-box single-line" data-val="true" data-val-date="The field Release Date must be a date." data-val-required="The Release Date field is required." id="ReleaseDate" name="ReleaseDate" type="date" value="1/1/1984" /> <span class="field-validation-valid help-inline" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span> </div> </div> <div class="control-group"> <label class="control-label" for="Genre">Genre</label> <div class="controls"> <input class="text-box single-line" id="Genre" name="Genre" type="text" value="Comedy" /> <span class="field-validation-valid help-inline" data-valmsg-for="Genre" data-valmsg-replace="true"></span> </div> </div> <div class="control-group"> <label class="control-label" for="Price">Price</label> <div class="controls"> <input class="text-box single-line" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" type="text" value="7.99" /> <span class="field-validation-valid help-inline" data-valmsg-for="Price" data-valmsg-replace="true"></span> </div> </div> <div class="form-actions no-color"> <input type="submit" value="Save" class="btn" /> </div> </fieldset> </form>
<input>元素是在HTML <form>元素的动作属性设置为post /Movies/Edit URL。表单数据将被张贴到服务器时,单击Save按钮。第二行显示了隐藏XSRF
@Html.AntiForgeryToken()调用生成的令牌。
处理POST请求
下面的清单显示了HttpPost版本的Edit操作方法。
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit([Bind(Include="ID,Title,ReleaseDate,Genre,Price")] Movie movie) { if (ModelState.IsValid) { db.Entry(movie).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(movie); }
ValidateAntiForgeryToken属性验证XSRF @Html.AntiForgeryToken()调用生成的令牌在视图中。
ASP.NET
MVC模型绑定器将发布表单值并创建一个电影作为电影参数传递的对象。ModelState.IsValid方法验证表单中提交的数据可以用来修改(编辑或更新)电影对象。如果数据是有效的,电影数据保存到电影db(MovieDBContext实例)的集合。新电影的数据保存到数据库中通过调用MovieDBContext中的SaveChanges方法。在保存数据,代码将用户重定向到索引MoviesController类的动作方法,它显示电影集合,包括相应的改变。
一旦客户端验证确定一个字段的值是无效的,显示一个错误消息。如果禁用JavaScript,您不会有客户端验证但服务器会检测到这个值是无效的,和表单的值将被显示错误消息。后在本教程中我们更详细地检查验证。
Html.ValidationMessageFor
协助在Edit.cshtml视图模板中显示适当的错误消息。
所有HttpGet方法遵循一个类似的模式。他们获得电影对象(或对象的列表,在Index的情况下),并通过模型的视图。Create方法传递一个空的电影对象来创建视图。所有的方法创建、编辑、删除或者修改数据HttpPost过载的方法。修改数据在一个HTTP
GET方法是一个安全风险,如博客条目所述 ASP.NET
MVC Tip #46 – Don’t use Delete Links because they create Security Holes,因为他们创造了安全漏洞。修改数据获得方法也违反了HTTP的最佳实践和其他建筑模式,它指定,GET请求不应改变应用程序的状态。换句话说,执行一个GET操作应该是一个安全的操作,没有副作用,不会修改您保存数据。