知识点4-1:哪些应该放在动作方法中?

      控制器是ASP.NET MVC应用程序的核心组件之一。它是一个含有一个或多个public方法(动作)的类,这些方法对应于特定的URL。这些动作充当着应用程序的“胶水”,将模型数据与应用程序的用户界面(视图)集合在一起。

      控制器应充当一种协调程序,它不应该真正包含任何业务逻辑,而是充当一种转换层的形式,将视图中的用户输入转换成业务逻辑对象,反之亦然。

1.手动映射视图模型

      在留言本这个例子中,GuestbookEntry类既作为域模型,也作为视图模型。它既表现了数据库中存储的数据,也表现了用户界面中的字段。

      对于像留言簿这样的小型应用程序,这是足够的。但是,随着应用程序复杂性的提升,当复杂的用户界面结构必须不直接映射模型的结构时,即视图数据与模型结构不同,往往需要将两者分开。比如,让我们对Guestbook应用程序添加一个新的页面,以显示每个用户已递交了多少评论的摘要,如图所示。

    为了创建这一屏幕,首先需要创建一个视图模型,它每一列含有一个属性——用户名和已递交的评论数:

    public class CommentSummary
    {
        public string UserName { get; set; }
        public string NumberOfComments { get; set; }
    }

      现在需要创建一个控制器动作,查询数据库以获取显示所必需的数据,然后将其注入CommentSummary类实例。

      public ActionResult CommentSummary()
        {
            var entries = from entry in _db.Entries
                          group entry by entry.Name into groupedByName
                          orderby groupedByName.Count() descending
                          select new CommentSummary
                          {
                              NumberOfComments = groupedByName.Count(),
                              UserName = groupedByName.Key
                          };
            return View(entries.ToList());
        }

     这里使用了LINQ来查询留言簿数据,并按用户名对递交的评论进行分组。接着将数据投影成视图模型实例,然后便可以将其传递给视图。

@model IEnumerable<Guestbook.Models.CommentSummary>

<table>
    <tr>
        <th>Number of comments</th>
        <th>User name</th>
    </tr>
    @foreach(var summaryRow in Model)
    {
        <tr>
            <td>@summaryRow.NumberOfComments</td>
            <td>@summaryRow.UserName</td>
        </tr>
    }
</table>

 2.输入验证

    回顾第2章,我们曾考擦了一个在GuestbookController的Create动作中接受用户输入的例子:

        [HttpPost]
        public ActionResult Create(GuestbookEntry entry)
        {
            entry.DateAdded = DateTime.Now;

            _db.Entries.Add(entry);
            _db.SaveChanges();

            return RedirectToAction("Index");
        }

      这个动作以GuestbookEntry对象形式简单地接受了New Comment页面所递交的输入,设置了日期,然后把它插入数据库。虽然这样可以工作得很好,但这实际上并不是最好的办法,没有任何验证。此刻用户可以递交未输入姓名或评论的表单。通过添加一些基本的验证,可以对此加以改进。
      我们要做的第一件事是,用Required注解属性来注释GuestbookEntry类的Name和Message属性。

    public class GuestbookEntry
    {
        public int Id { get; set; }
        
        [Required]
        public string Name { get; set; }

        [Required]
        public string Message { get; set; }

        public DateTime DateAdded { get; set; }
    }

      Required注解属性位于System.ComponentModel.DataAnnotations命名空间,并提供了对一个对象的特定属性进行验证的方式。一旦做了注释,MVC将在调用Create动作时自动地验证这些属性。通过检查ModelState.IsValid属性,可以检查验证是成功或失败,然后决定验证失败时做什么。以下是Create动作更新后的版本。

        [HttpPost]
        public ActionResult Create(GuestbookEntry entry)
        {
            if (ModelState.IsValid)
            {
                entry.DateAdded = DateTime.Now;

                _db.Entries.Add(entry);
                _db.SaveChanges();

                return RedirectToAction("Index");
            }

            return View(entry);
        }

      这一次,我们不是简单地在数据库中存储新条目,而是首先检查ModelState.IsValid是否返回true。如果是,便还像前面那样保存这一新条目。然而,如果失败,则重新渲染Create视图,这让用户能够在再次提交之前纠正任何问题。
      通过调用Html.ValidationSummary方法,我们可以在视图中显示验证失败所生成的错误消息。

<h2>添加留言</h2>
@Html.ValidationSummary()

@using (Html.BeginForm())
{
    <p>Please enter your name:</p>
    @Html.TextBox("Name")

    <p>Please enter your message:</p>
    @Html.TextArea("Message", new { rows = 10, cols = 40 })

    <br />
    <br />
    <input type="submit" value="Submit Entry" />
}

      除了在视图的顶部调用ValidationSummary方法外,还要注意到,现在也使用了MVC的HTML辅助器来生成页面上的文本输入。使用这些辅助器的一个好处是,MVC将自动检测验证错误消息,并运用一个CSS的class指示该字段有错误。

    在图中所看到的错误消息是ASP.NET MVC默认用于必需字段的错误消息。我们可以对其加以重写并使用自己的消息,只要修改Required注解属性的声明,让其包含一条自定义消息即可:

        [Required(ErrorMessage="Please enter your name")]
        public string Name { get; set; }

 

posted @ 2014-10-08 23:12  liesl  阅读(199)  评论(0编辑  收藏  举报