ASP.NET MVC 5 入门(07):检查 Edit 方法和编辑视图

原文:https://docs.microsoft.com/zh-cn/aspnet/mvc/overview/getting-started/introduction/examining-the-edit-methods-and-edit-view

作者: Rick Anderson

ASP.NET MVC 5 入门

ASP.NET MVC 5 简介

此教程的更新版本可在此处使用最新版本的Visual Studio 新教程使用ASP.NET CORE MVC,这在本教程中提供了许多改进。

本教程介绍具有控制器和视图的 ASP.NET Core MVC。 Razor 页面是 ASP.NET Core 2.0 中的一个新选择,它是基于页面的编程模型,可以实现更简单、更高效地生成 Web UI。 建议先尝试 Razor 页面教程,再使用 MVC 版本。 Razor 页面教程:

  • 易于关注。
  • 涵盖更多功能。
  • 是开发新应用程序的首选方法。

以下教程系列介绍了GitHub上的 ASP.NET MVC: Source

在本部分中,你将检查电影控制器的生成 Edit 操作方法和视图。 但首先我们要 diversion,使发布日期看起来更好。 打开ModelsMovie.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特性指定数据的类型,在本例中为日期,因此不显示存储在字段中的时间信息。 Chrome 浏览器中的 bug 所需的DisplayFormat属性不正确地呈现日期格式。

运行应用程序并浏览到 Movies 控制器。 将鼠标指针停留在编辑链接上可查看它所链接到的 URL。

EditLink_sm

编辑链接是由ViewsMoviesIndex.cshtml视图中的 Html.ActionLink 方法生成的:

@Html.ActionLink("Edit", "Edit", new { id=item.ID })

Html.ActionLink

Html 对象是一个使用WebViewPage基类上的属性公开的帮助器。 利用帮助程序的 ActionLink 方法,可以轻松地动态生成链接到控制器操作方法的 HTML 超链接。 ActionLink 方法的第一个参数是要呈现的链接文本(例如,<a>Edit Me</a>)。 第二个参数是要调用的操作方法的名称(在本例中为 Edit 操作)。 最终参数是生成路由数据的匿名对象(在本例中为 ID 4)。

http://localhost:1234/Movies/Edit/4上图中显示的生成的链接。 默认路由(在应用_StartRouteConfig.cs中建立)采用 URL 模式 {controller}/{action}/{id} 因此,ASP.NET 会将 http://localhost:1234/Movies/Edit/4 转换为 Movies 控制器 Edit 操作方法的请求,该参数 ID 等于4。 应用程序_StartRouteConfig.cs文件中检查以下代码。 Maproute.html方法用于将 HTTP 请求路由到正确的控制器和操作方法,并提供可选的 ID 参数。 Maproute.html方法还由HtmlHelpers (如 ActionLink)用于在给定控制器、操作方法和任何路由数据的情况下生成 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 还将参数 ID 3 传递给 Movies 控制器的 Edit 操作方法。

EditQueryString

打开 Movies 控制器。 下面显示了两个 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 https://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);
}

请注意第二个 Edit 操作方法的前面是 HttpPost 特性。 此特性指定只能为 POST 请求调用 Edit 方法的重载。 您可以将 HttpGet 特性应用于第一个编辑方法,但这不是必需的,因为它是默认值。 (我们将引用隐式分配 HttpGet 属性作为 HttpGet 方法的操作方法。)绑定属性是另一个重要的安全机制,可防止黑客将数据过度发送到您的模型。 只应在要更改的 bind 特性中包括属性。 可以在我的过多发布安全说明中阅读过多发布和 bind 属性。 在本教程中使用的简单模型中,将绑定模型中的所有数据。 ValidateAntiForgeryToken属性用于防止请求伪造,并与编辑视图文件(ViewsMoviesEdit.cshtml)中的 @Html.AntiForgeryToken() 配对,部分如下所示:

@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() 生成一个隐藏的窗体 anti-spam 标记,该标记必须与 Movies 控制器的 Edit 方法匹配。 在 MVC 中,可以在我的教程XSRF/CSRF 防护中阅读有关跨站点请求伪造(也称为 XSRF 或 CSRF)的详细信息。

HttpGet Edit 方法采用 "影片 ID" 参数,使用实体框架 Find 方法查找电影,并将所选电影返回到 "编辑" 视图。 如果找不到电影,则返回HttpNotFound 当基架系统创建“编辑”视图时,它会检查 Movie 类并创建代码为类的每个属性呈现 <label><input> 元素。 下面的示例演示了 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.Movie 语句,这会指定该视图要求视图模板的模型类型为 Movie

基架代码使用多个帮助器方法来简化 HTML 标记。 Html.LabelFor帮助程序显示字段的名称("标题"、"ReleaseDate"、"流派"或 "价格")。 Html.EditorFor帮助器呈现 HTML <input> 元素。 Html.ValidationMessageFor帮助器将显示与该属性相关联的所有验证消息。

运行应用程序并导航到 /Movies URL。 点击“编辑”链接。 在浏览器中查看页面的源。 窗体元素的 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> 元素中,其 action 特性设置为 post 到 /Movies/Edit URL。 单击 "保存" 按钮后,窗体数据将发布到服务器。 第二行显示 @Html.AntiForgeryToken() 调用生成的隐藏的XSRF标记。

一、处理 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属性验证视图中 @Html.AntiForgeryToken() 调用生成的XSRF标记。

ASP.NET MVC 模型联编程序将使用已发布的窗体值,并创建一个作为 movie 参数传递的 Movie 对象。 ModelState.IsValid 验证在表单中提交的数据是否可用于修改(编辑或更新) Movie 的对象。 如果数据有效,则影片数据将保存到 dbMovieDBContext 实例)的 Movies 集合。 通过调用 MovieDBContextSaveChanges 方法,将新的电影数据保存到数据库中。 保存数据后,代码将用户重定向到 Index 类的 MoviesController 操作方法,此方法显示电影集合,包括刚才所做的更改。

一旦客户端验证确定字段的值无效,就会显示一条错误消息。 如果禁用 JavaScript,将禁用客户端验证。 但是,服务器会检测到已发布的值无效,并且将显示错误消息的窗体值。

稍后将在本教程中更详细地检查验证。

编辑. view 模板中的 Html.ValidationMessageFor 帮助器负责显示适当的错误消息。

abcNotValid

所有 HttpGet 方法都遵循类似的模式。 它们获取影片对象(或对象列表(如果 Index),并将模型传递给视图。 Create 方法将空电影对象传递到 "创建" 视图。 在方法的 HttpPost 重载中,创建、编辑、删除或以其他方式修改数据的所有方法都执行此操作。 修改 HTTP GET 方法中的数据存在安全风险,如博客文章ASP.NET MVC Tip #46 中所述–不要使用删除链接,因为它们创建了安全漏洞 修改 GET 方法中的数据也违反了 HTTP 最佳做法和体系结构REST模式,该模式指定 GET 请求不应更改应用程序的状态。 换句话说,执行 GET 操作应是没有任何隐患的安全操作,也不会修改持久数据。

二、非英语区域设置的 jQuery 验证

如果你使用的是美国英语计算机,则可以跳过本部分并转到下一教程。 你可以在此处下载本教程的全球化版本。 有关国际化的优秀两部分教程,请参阅Nadeem 的 ASP.NET MVC 5 国际化

Note

若要支持使用逗号("、")作为小数点和非美国英语日期格式的非英语区域设置的 jQuery 验证,你必须将全球化和特定区域性/全球化. .js文件(从https://github.com/jquery/globalize )和 JavaScript 用于 Globalize.parseFloat 可以从 NuGet 获取 jQuery 非英语验证。 (如果使用的是英语区域设置,请不要安装全球化。)

  1. 从 "工具" 菜单中,单击 " Nuget 包管理器",然后单击 "管理解决方案的 NuGet 包"。

  2. 在左侧窗格中,选择 "浏览" (请参阅下图。)

  3. 在 "输入" 框中,输入 * 全球化 * *。

    选择 "jQuery.Validation.Globalize",选择 "MvcMovie",然后单击 "安装"。 Scriptsjquery.globalizeglobalize.js文件将添加到你的项目中。 * Scriptsjquery.globalizecultures* 文件夹将包含许多区域性 JavaScript 文件。 请注意,安装此包可能需要5分钟。

    下面的代码演示对 ViewsMoviesEdit.cshtml 文件所做的修改:

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")

<script src="~/Scripts/globalize/globalize.js"></script>
<script src="~/Scripts/globalize/cultures/globalize.culture.@(System.Threading.Thread.CurrentThread.CurrentCulture.Name).js"></script>
<script>
    $.validator.methods.number = function (value, element) {
        return this.optional(element) ||
            !isNaN(Globalize.parseFloat(value));
    }
    $(document).ready(function () {
        Globalize.culture('@(System.Threading.Thread.CurrentThread.CurrentCulture.Name)');
    });
</script>
<script>
    jQuery.extend(jQuery.validator.methods, {
        range: function (value, element, param) {
            //Use the Globalization plugin to parse the value
            var val = Globalize.parseFloat(value);
            return this.optional(element) || (
                val >= param[0] && val <= param[1]);
        }
    });
    $.validator.methods.date = function (value, element) {
        return this.optional(element) ||
            Globalize.parseDate(value) ||
            Globalize.parseDate(value, "yyyy-MM-dd");
    }
</script>
}

若要避免在每个编辑视图中重复此代码,可以将其移动到布局文件中。 若要优化脚本下载,请参阅我的教程捆绑和缩减

有关详细信息,请参阅ASP.NET mvc 3 国际化ASP.NET MVC 3 国际化-第2部分(NerdDinner)

作为临时修补程序,如果无法在区域设置中使用验证,则可以强制计算机使用美国英语,或者可以在浏览器中禁用 JavaScript。 若要强制计算机使用美国英语,可以将全球化元素添加到项目根web.config文件中。 下面的代码演示将区域性设置为美国英语的全球化元素。

<system.web>
    <globalization culture ="en-US" />
    <!--elements removed for clarity-->
  </system.web>

在下一教程中,我们将实现搜索功能。

原文地址:https://www.cnblogs.com/springsnow/p/13264840.html