010.Controller methods and views --【控制器方法与视图】

时间:2022-05-10 20:36:38

索引:

目录索引

Controller methods and views

控制器方法与视图

2017-3-7 9 分钟阅读时长 作者

By Rick Anderson

We have a good start to the movie app, but the presentation is not ideal.

我们在movie 应用上已经有了一个好的开始,但是表现层不是很理想。

We don't want to see the time (12:00:00 AM in the image below) and ReleaseDateshould be two words.

我们不想看到下图中显示的(12:00:00 AM)并且 ReleaseDate 字段应该显示为两个单词。

010.Controller methods and views --【控制器方法与视图】

Open the Models/Movie.cs file and add the highlighted lines shown below:

打开 Models/Movie.cs 文件并且添加下面高亮行的代码:

 using System;

 using System.Collections.Generic;

 using System.Linq;

 using System.Threading.Tasks;

 namespace MvcMovie.Models

 {

     public class Movie

     {

         public int ID { get; set; }

         public string Title { get; set; }

         [Display(Name = "Release Date")]

         [DataType(DataType.Date)]

         public DateTime ReleaseDate { get; set; }

         public string Genre { get; set; }

         public decimal Price { get; set; }

     }

 }

C# code

Right click on a red squiggly line > Quick Actions and Refactorings.

在红波浪线上右击,选择 Quick Actions and Refactorings.

010.Controller methods and views --【控制器方法与视图】

Tap using System.ComponentModel.DataAnnotations;

点击 using System.ComponentModel.DataAnnotations

010.Controller methods and views --【控制器方法与视图】

Visual studio adds using System.ComponentModel.DataAnnotations;.

VS将自动添加 using System.ComponentModel.DataAnnotations 。

Let's remove the using statements that are not needed.

让移除不需要的 using 语句 。

They show up by default in a light grey font. Right click anywhere in the Movie.cs file > Remove and Sort Usings.

他们默认以灰色字体显示。右击 Movie.cs 文件的任何地方,选择 Remove and Sort Usings

010.Controller methods and views --【控制器方法与视图】

The updated code:

更新后的代码如下:

 using System;

 using System.ComponentModel.DataAnnotations;

 namespace MvcMovie.Models

 {

     public class Movie

     {

         public int ID { get; set; }

         public string Title { get; set; }

         [Display(Name = "Release Date")]

         [DataType(DataType.Date)]

         public DateTime ReleaseDate { get; set; }

         public string Genre { get; set; }

         public decimal Price { get; set; }

     }

 }

C# code

We'll cover DataAnnotations in the next tutorial.

我们将在接下来的教程中讲解数据注解特性。

The Display attribute specifies what to display for the name of a field (in this case "Release Date" instead of "ReleaseDate").

Display 特性特别的指定了该字段在界面显示时所要显示的名字(用 Release Date 代替了 ReleaseDate)。

The DataType attribute specifies the type of the data (Date), so the time information stored in the field is not displayed.

DataType 特性特别指定了数据的显示类型(日期),因此字段里面存储的时间信息就不再显示了。

Browse to the Movies controller and hold the mouse pointer over an Edit link to see the target URL.

导航到 Movies 地址,在页面上将鼠标放到 Edit 链接上,并查看目标URL.

010.Controller methods and views --【控制器方法与视图】

The EditDetails, and Delete links are generated by the MVC Core Anchor Tag Helper in the Views/Movies/Index.cshtml file.

Views/Movies/Index.cshtml  文件中的 EditDetails和 Delete 链接由mvc链接帮助类自动生成的。

         <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |

         <a asp-action="Details" asp-route-id="@item.ID">Details</a> |

         <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>

     </td>

 </tr>

HTML Code

Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files.

Tag Helpers 是在服务端参与产生与渲染HTML的。

In the code above,

在上面的代码中,

the AnchorTagHelperdynamically generates the HTML href attribute value from the controller action method and route id.

AnchorTagHelper 动态的生成了html中的href 特征属性的值 (控制器方法与方法的id参数)。

You use View Source from your favorite browser or use the developer tools to examine the generated markup.

你可以使用浏览器的 View Source 或开发工具查看 自动生成的 html 标记。

A portion of the generated HTML is shown below:

部分html如下所示:

  <td>

     <a href = "/Movies/Edit/4" > Edit </ a > |

     < a href="/Movies/Details/4">Details</a> |

     <a href = "/Movies/Delete/4" > Delete </ a >

 </ td >

HTML Code

Recall the format for routing set in the Startup.cs file:

回想 Startup.cs 文件中的路由设置,如下:

 app.UseMvc(routes =>

 {

     routes.MapRoute(

         name: "default",

         template: "{controller=Home}/{action=Index}/{id?}");

 });

C# code

ASP.NET Core translates http://localhost:1234/Movies/Edit/4 into a request to the Edit action method of the Movies controller with the parameter Id of 4. (Controller methods are also known as action methods.)

Asp.net core 翻译 http://localhost:1234/Movies/Edit/4 地址为对 Movies 控制器中方法Edit 的请求,并且参数为4.

Tag Helpers are one of the most popular new features in ASP.NET Core.

Tag Helpers 是asp.net core 中最受欢迎的特点之一。

See Additional resources for more information.

查看 Additional resources 了解更多信息。

Open the Movies controller and examine the two Edit action methods.

打开 Movies  控制器,查看两个 Edit  方法的代码。

The following code shows the HTTP GET Edit method, which fetches the movie and populates the edit form generated by the Edit.cshtml Razor file.

下面的代码是 HTTP GET Edit 方法,他读取了movie数据并填充了由 Edit.cshtml 文件生成的编辑表单。

 // GET: Movies/Edit/5

 public async Task<IActionResult> Edit(int? id)

 {

     if (id == null)

     {

         return NotFound();

     }

     var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);

     if (movie == null)

     {

         return NotFound();

     }

     return View(movie);

 }

C# code

The following code shows the HTTP POST Edit method, which processes the posted movie values:

下面的代码展示了 HTTP POST Edit 方法,他处理了post请求过来的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 async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price")] Movie movie)

 {

     if (id != movie.ID)

     {

         return NotFound();

     }

     if (ModelState.IsValid)

     {

         try

         {

             _context.Update(movie);

             await _context.SaveChangesAsync();

         }

         catch (DbUpdateConcurrencyException)

         {

             if (!MovieExists(movie.ID))

             {

                 return NotFound();

             }

             else

             {

                 throw;

             }

         }

         return RedirectToAction("Index");

     }

     return View(movie);

 }

C# code

The [Bind] attribute is one way to protect against over-posting.

[Bind] 特性标记是一种post攻击防护方式。

You should only include properties in the [Bind] attribute that you want to change.

你应当只做 [Bind] 特征类中包含的字段的变更。

See Protect your controller from over-posting for more information.

查看 Protect your controller from over-posting 以获得更多信息。

ViewModels provide an alternative approach to prevent over-posting.

ViewModels 提供一种预防 over-posting 攻击的方式。

Notice the second Edit action method is preceded by the [HttpPost] attribute.

注意第二个 Edit 方法被 [HttpPost] 特征类修饰。

 // 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 async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price")] Movie movie)

 {

     if (id != movie.ID)

     {

         return NotFound();

     }

     if (ModelState.IsValid)

     {

         try

         {

             _context.Update(movie);

             await _context.SaveChangesAsync();

         }

         catch (DbUpdateConcurrencyException)

         {

             if (!MovieExists(movie.ID))

             {

                 return NotFound();

             }

             else

             {

                 throw;

             }

         }

         return RedirectToAction("Index");

     }

     return View(movie);

 }

C# code

The HttpPost attribute specifies that this Edit method can be invoked only for POST requests.

HttpPost 标记特别指定了 Edit 方法只能被 POST 请求调用。

You could apply the [HttpGet] attribute to the first edit method, but that's not necessary because [HttpGet] is the default.

你可以在第一个 edit 方法上使用 [HttpGet] 特征类,单他不是必须的,因为方法默认是 [HttpGet] 请求的。

The ValidateAntiForgeryToken attribute is used to prevent forgery of a requestand is paired up with an anti-forgery token generated in the edit view file (Views/Movies/Edit.cshtml).

ValidateAntiForgeryToken 标记类使用了预防伪造请求,并与 edit 视图生成的反伪造令牌是配对的。

The edit view file generates the anti-forgery token with the Form Tag Helper.

edit 视图生成的anti-forgery 令牌是通过 Form Tag Helper 生成的。

 <form asp-action="Edit">

HTML Code

The Form Tag Helper generates a hidden anti-forgery token that must match the [ValidateAntiForgeryToken] generated anti-forgery token in the Edit method of the Movies controller.

Form Tag Helper 生成了一个隐藏域的令牌字段,并且他是匹配Movies控制器中Edit 方法上的[ValidateAntiForgeryToken] 标记生成的令牌的。

For more information, see Anti-Request Forgery.

查看  Anti-Request Forgery ,以获得更多信息。

The HttpGet Edit method takes the movie ID parameter, looks up the movie using the Entity Framework SingleOrDefaultAsync method, and returns the selected movie to the Edit view.

HttpGet Edit 方法获取 ID 参数,查看 EF 的 SingleOrDefaultAsync 方法,它会查找并将movie数据返回给 Edit 视图。

If a movie cannot be found, NotFound (HTTP 404) is returned.

如果movie数据没有找到,将返回 NotFound 。

 // GET: Movies/Edit/5

 public async Task<IActionResult> Edit(int? id)

 {

     if (id == null)

     {

         return NotFound();

     }

     var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);

     if (movie == null)

     {

         return NotFound();

     }

     return View(movie);

 }

C# code

When the scaffolding system created the Edit view, it examined the Movie class and created code to render <label> and <input> elements for each property of the class.

当MVC基架系统创建了 Edit 视图,它会自动检查 Movie 类的每个属性,并未每个属性创建HTML元素。

The following example shows the Edit view that was generated by the Visual Studio scaffolding system:

下面的例子展示了VS基架系统自动生成的 Edit 视图:

 @model MvcMovie.Models.Movie

 @{

     ViewData["Title"] = "Edit";

 }

 <h2>Edit</h2>

 <form asp-action="Edit">

     <div class="form-horizontal">

         <h4>Movie</h4>

         <hr />

         <div asp-validation-summary="ModelOnly" class="text-danger"></div>

     <input type="hidden" asp-for="ID" />

         <div class="form-group">

             <label asp-for="Title" class="col-md-2 control-label"></label>

             <div class="col-md-10">

                 <input asp-for="Title" class="form-control" />

                 <span asp-validation-for="Title" class="text-danger"></span>

             </div>

         </div>

         <div class="form-group">

             <label asp-for="ReleaseDate" class="col-md-2 control-label"></label>

             <div class="col-md-10">

                 <input asp-for="ReleaseDate" class="form-control" />

                 <span asp-validation-for="ReleaseDate" class="text-danger"></span>

             </div>

         </div>

         <div class="form-group">

             <label asp-for="Genre" class="col-md-2 control-label"></label>

             <div class="col-md-10">

                 <input asp-for="Genre" class="form-control" />

                 <span asp-validation-for="Genre" class="text-danger"></span>

             </div>

         </div>

         <div class="form-group">

             <label asp-for="Price" class="col-md-2 control-label"></label>

             <div class="col-md-10">

                 <input asp-for="Price" class="form-control" />

                 <span asp-validation-for="Price" class="text-danger"></span>

             </div>

         </div>

         <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>

 </form>

 <div>

     <a asp-action="Index">Back to List</a>

 </div>

 @section Scripts {

     @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}

 }

HTML Code

Notice how the view template has a @model MvcMovie.Models.Movie statement at the top of the file.

注意视图文件在顶部为什么会有 @model MvcMovie.Models.Movie 这样一句话。

@model MvcMovie.Models.Movie specifies that the view expects the model for the view template to be of type Movie.

@model 特别指定了视图所期望的模型类型是 Movie 类型。

The scaffolded code uses several Tag Helper methods to streamline the HTML markup.

基架代码使用服务端标记帮助方法来精简HTML标签写法。

The - Label Tag Helper displays the name of the field ("Title", "ReleaseDate", "Genre", or "Price").

Label Tag Helper 显示字段名称的名字。

The Input Tag Helper renders an HTML <input> element.

Input Tag Helper 渲染HTML <input> 元素。

The Validation Tag Helper displays any validation messages associated with that property.

Validation Tag Helper 显示所有的关联在属性上的验证信息。

Run the application and navigate to the /Movies URL. Click an Edit link.

运行程序并导航至 /Movies ,点击 Edit 链接。

In the browser, view the source for the page. The generated HTML for the <form>element is shown below.

在浏览器中,查看页面源码。自动生成的 <form> 元素如下所示:

 <form action="/Movies/Edit/7" method="post">

     <div class="form-horizontal">

         <h4>Movie</h4>

         <hr />

         <div class="text-danger" />

         <input type="hidden" data-val="true" data-val-required="The ID field is required." id="ID" name="ID" value="7" />

         <div class="form-group">

             <label class="control-label col-md-2" for="Genre" />

             <div class="col-md-10">

                 <input class="form-control" type="text" id="Genre" name="Genre" value="Western" />

                 <span class="text-danger field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>

             </div>

         </div>

         <div class="form-group">

             <label class="control-label col-md-2" for="Price" />

             <div class="col-md-10">

                 <input class="form-control" type="text" 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" value="3.99" />

                 <span class="text-danger field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>

             </div>

         </div>

         <!-- Markup 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>

     <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Inyxgp63fRFqUePGvuI5jGZsloJu1L7X9le1gy7NCIlSduCRx9jDQClrV9pOTTmqUyXnJBXhmrjcUVDJyDUMm7-MF_9rK8aAZdRdlOri7FmKVkRe_2v5LIHGKFcTjPrWPYnc9AdSbomkiOSaTEg7RU" />

 </form>

HTML Code

The <input> elements are in an HTML <form> element whose action attribute is set to post to the /Movies/Edit/id URL.

<input> 元素在HTML <form> 内的form的 action 属性被赋值为 /Movies/Edit/id 的地址。

The form data will be posted to the server when the Save button is clicked.

当 Save 被点击后,表单中的数据将被发送至服务器。

The last line before the closing </form>element shows the hidden XSRF token generated by the Form Tag Helper.

在 </form> 元素上的最后一行是 由 Form Tag Helper 自动生成的 XSRF 令牌。

Processing the POST Request

处理 POST 请求

The following listing shows the [HttpPost] version of the Edit action method.

下面的 Edit 方法展示了如何被 [HttpPost] 特征类修饰。

 // 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 async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price")] Movie movie)

 {

     if (id != movie.ID)

     {

         return NotFound();

     }

     if (ModelState.IsValid)

     {

         try

         {

             _context.Update(movie);

             await _context.SaveChangesAsync();

         }

         catch (DbUpdateConcurrencyException)

         {

             if (!MovieExists(movie.ID))

             {

                 return NotFound();

             }

             else

             {

                 throw;

             }

         }

         return RedirectToAction("Index");

     }

     return View(movie);

 }

C# code

The [ValidateAntiForgeryToken] attribute validates the hidden XSRF token generated by the anti-forgery token generator in the Form Tag Helper

[ValidateAntiForgeryToken] 特征类将会验证 由 Form Tag Helper 生成的隐藏域中的 XSRF 令牌,

The model binding system takes the posted form values and creates a Movieobject that's passed as the movie parameter.

模型绑定系统将会读取post传递过来的表单数据并创建 Movie 对象并传递给 movie 参数。

The ModelState.IsValid method verifies that the data submitted in the form can be used to modify (edit or update) a Movie object.

ModelState.IsValid 这个方法将会验证提交的数据是否可被用于 Movie 对象的增删改。

If the data is valid it's saved.

如果数据有效,数据将会被保存。

The updated (edited) movie data is saved to the database by calling the SaveChangesAsync method of database context.

被更新的数据将会调用 SaveChangesAsync 方法保存到数据库中。

After saving the data, the code redirects the user to the Index action method of the MoviesController class, which displays the movie collection, including the changes just made.

在保存数据后,代码会重定向到 Movies 控制器的 Index方法,它将会显示 movie 列表,其中包括刚做过变更的 movie 数据。

Before the form is posted to the server, client side validation checks any validation rules on the fields.

在表单被提交到服务器前,客户端将会检查在字段上的所有验证规则。

If there are any validation errors, an error message is displayed and the form is not posted.

如果有任何验证错误,错误信息就会显示出来,并且表单就不会被提交。

If JavaScript is disabled, you won't have client side validation but the server will detect the posted values that are not valid, and the form values will be redisplayed with error messages.

如果JS被禁用,你不会有客户端的验证信息,但是服务端将会继续验证字段值是否有效,并且表单将会显示出错误信息。

Later in the tutorial we examine Model Validation in more detail.

在接下来的教程中我们将会学习到模型验证的更多细节信息。

The Validation Tag Helper in the Views/Movies/Edit.cshtml view template takes care of displaying appropriate error messages.

Views/Movies/Edit.cshtml 视图模板中 Validation Tag Helper 将会显示出适当的错误信息。

010.Controller methods and views --【控制器方法与视图】

All the HttpGet methods in the movie controller follow a similar pattern.

在movie控制器中的所有 HttpGet 方法都遵循相似的模式。

They get a movie object (or list of objects, in the case of Index), and pass the object (model) to the view.

他们读取一个movie对象,并将这个对象传递给视图。

The Create method passes an empty movie object to the Create view.

Create 方法传递一个空的movie对象到 Create 视图。

All the methods that create, edit, delete, or otherwise modify data do so in the [HttpPost] overload of the method.

所有的 create, edit, delete 或其它修改数据的方法都是这样做的,包括 [HttpPost] 修饰的方法。

Modifying data in an HTTP GETmethod is a security risk.

在 HTTP GET 方法中修改数据是一个安全上的冒险。

Modifying data in an HTTP GET method also violates HTTP best practices and the architectural REST pattern, which specifies that GET requests should not change the state of your application.

用 HTTP GET 方法修改数据违反了HTTP最佳实践和rest风格结构,它们特别指出了 GET 请求不可以改变应用数据状态。

In other words, performing a GET operation should be a safe operation that has no side effects and doesn't modify your persisted data.

换句话说,执行一个 GET 操作,应该是一个没有任何副作用并且不会修改任何持久化数据的安全操作动作。

Additional resources

额外资源

                                         蒙

                                    2017-08-16 18:26 周三