七天学会ASP.NET MVC (三)——ASP.Net MVC 数据处理

第三天我们将学习Asp.Net中数据处理功能,了解数据访问层,EF,以及EF中常用的代码实现方式,创建数据访问层和数据入口,处理Post数据,以及数据验证等功能。

系列文章

七天学会ASP.NET MVC (一)——深入理解ASP.NET MVC

七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递

七天学会ASP.NET MVC (三)——ASP.Net MVC 数据处理

七天学会ASP.NET MVC (四)——用户授权认证问题

七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理

七天学会ASP.NET MVC (六)——线程问题、异常处理、自定义URL

七天学会ASP.NET MVC(七)——创建单页应用

目录:

数据访问层

实体框架(EF)简述

什么是代码优先的方法?

实验8——在项目中添加数据访问层

关于实验8

实验9——创建数据输入屏幕

实验10——获取服务端或控制器端传递的数据。

实验11——重置及取消按钮

实验12——保存数据。库记录并更新表格

实验13——添加服务器端验证

实验14——自定义服务器端验证

结论

数据访问层

在实际开发中,如果一个项目不包含任何数据库,那么这个项目是不完整的,我们在一二节实例中未涉及数据库,在本节开始,实验8中讲解一个关于数据库和数据库层的实例。

本节将使用SQL Server和EF(Entity Framework)创建相关的数据库及数据库访问层。

简述实体框架(EF)

EF是一种ORM工具,ORM表示对象关联映射。

在RDMS中,对象称为表格和列对象,而在.net中(面向对象)称为类,对象以及属性。

任何数据驱动的应用实现的方式有两种:

1. 通过代码与数据库关联(称为数据访问层或数据逻辑层)

2. 通过编写代码将数据库数据映射到面向对象数据,或反向操作。

ORM是一种能够自动完成这两种方式的工具。EF是微软的ORM工具。

什么是代码优先的方法?

EF提供了三种方式来实现项目:

l 数据库优先方法——创建数据库,包含表,列以及表之间的关系等,EF会根据数据库生成相应的Model类(业务实体)及数据访问层代码。

l 模型优先方法——模型优先指模型类及模型之间的关系是由Model设计人员在VS中手动生成和设计的,EF将模型生成数据访问层和数据库。

l 代码优先方法——代码优先指手动创建POCO类。这些类之间的关系使用代码定义。当应用程序首次执行时,EF将在数据库服务器中自动生成数据访问层以及相应的数据库。

什么是POCO类?

POCO即Plain Old CLR对象,POCO类就是已经创建的简单.Net类。在上两节的实例中,Employee类就是一个简单的POCO类。

实验8——添加数据访问层

1. 创建数据库

连接SQL SERVER ,创建数据库 “SalesERPDB”。

2. 创建连接字符串(ConnectionString

打开Web.Config 文件,在< Configuration >标签内添加以下代码:

   1:  <connectionStrings>
   2:  <add connectionString="Data Source=(local);Initial Catalog=SalesERPDB;Integrated Security=True"
   3:          name="SalesERPDAL"       
   4:          providerName="System.Data.SqlClient"/>
   5:  </connectionStrings>

3. 添加EF引用

右击项目->管理Nuget 包。选择Entity Framework 并点击安装。

4. 创建数据访问层

  • 在根目录下,新建文件夹”Data Access Layer“,并在Data Access Layer文件夹中新建类” SalesERPDAL “
  • 在类文件顶部添加 Using System.Data.Entity代码。
  • 继承DbContext类
   1:  public class SalesERPDAL: DbContext
   2:  {
   3:  }

5. 创建Employee类的主键

打开Employee类,输入using语句

   1:  using System.ComponentModel.DataAnnotations;

添加Employee的属性,并使用Key 关键字标识主键。

public class Employee
{
    [Key]
    public int EmployeeId  { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Salary { get; set; }
}

6. 定义映射关系

在SalesERPDAL类文件输入using语句。

   1:  using WebApplication1.Models;

在 SalesERPDAL 类中重写 OnModelCreating方法,代码如下:

   1:  protected override void OnModelCreating(DbModelBuilder modelBuilder)
   2:  {
   3:      modelBuilder.Entity<employee>().ToTable("TblEmployee");
   4:      base.OnModelCreating(modelBuilder);
   5:  }
   6:  </employee>

注意:上述代码中提到“TblEmployee”是表名称,是运行时自动生成的。

7. 在数据库中添加新属性Employee

在 SalesERPDAL 类中添加新属性 Employee。

   1:  public DbSet<employee> Employees{get;set;}
   2:  </employee>

DbSet表示数据库中能够被查询的所有Employee

8. 改变业务层代码,并从数据库中获取数据

打开 EmployeeBusinessLayer 类,输入Using 语句。

   1:  using WebApplication1.DataAccessLayer;

修改GetEmployees 方法:

   1:  public List<employee> GetEmployees()
   2:  {
   3:      SalesERPDAL salesDal = new SalesERPDAL();
   4:      return salesDal.Employees.ToList();
   5:  }
   6:  </employee>

9. 运行并测试

右击,查看并没有任何Employee的表格,查看数据库文件,我们会看到 TblEmployee 表

10. 插入测试数据

在TblEmployee 中插入一些测试数据

11. 运行程序

关于实验8

什么是数据集?

DbSet数据集是数据库方面的概念 ,指数据库中可以查询的实体的集合。当执行Linq 查询时,Dbset对象能够将查询内部转换,并触发数据库。

在本实例中,数据集是Employees,是所有Employee的实体的集合。当每次需要访问Employees时,会获取“TblEmployee”的所有记录,并转换为Employee对象,返回Employee对象集。

如何连接数据访问层和数据库?

数据访问层和数据库之间的映射通过名称实现的,在实验8中,ConnectionString(连接字符串)的名称和数据访问层的类名称是相同的,都是SalesERPDAL,因此会自动实现映射。

连接字符串的名称可以改变吗?

可以改变,在实验8中,在数据访问层中定义了构造函数,如下:

   1:  public SalesERPDAL():base("NewName")
   2:  {
   3:  }

实验8已经完成,相信大家已经了解基本的原理和操作,接下来我们将做一些改变,使得每件事情都变得有组织有意义:

1. 重命名

  • 将“TestController”改成 “EmployeeController”
  • GetView的行为方法改为Index
  • Views文件夹目录下的Test 文件夹改成Employee
  • MyView的View 改为“Index”

2. 删除EmployeeListViewModel 的 UserName  属性

3. 删除View中的 UserName

打开 Views/Employee.Index.cshtml View ,删除 UserName ,即删除以下代码:

   1:  Hello @Model.UserName
   2:  <hr />

4. 修改 EmployeeController 中的 Index方法

根据以下代码修改Index 方法,执行时URL会变成  “…./Employee/Index”

public ActionResult Index()
{
    &hellip;&hellip;
    &hellip;&hellip;
    &hellip;&hellip;
    employeeListViewModel.Employees = empViewModels;
    //employeeListViewModel.UserName = "Admin";-->Remove this line -->Change1
    return View("Index", employeeListViewModel);//-->Change View Name -->Change 2
}

实验 9——创建数据入口(Data Entry Screen)

1. 新建 action  方法

在 EmployeeController 中新建 “AddNew”action 方法:

   1:  public ActionResult AddNew()
   2:  {
   3:      return View("CreateEmployee");
   4:  }

2. 创建 View

在View/Employee目录下 新建 View 命名为:CreateEmployee。

   1:  @{
   2:      Layout = null;
   3:  }
   4:  <!DOCTYPE html>
   5:  <html>
   6:      <head>
   7:        <meta name="viewport" content="width=device-width" />
   8:        <title>CreateEmployee</title>
   9:      </head>
  10:      <body>
  11:        <div>
  12:           <form action="/Employee/SaveEmployee" method="post">
  13:              First Name: <input type="text" id="TxtFName" name="FirstName" value="" /><br />
  14:              Last Name: <input type="text" id="TxtLName" name="LastName" value="" /><br />
  15:              Salary: <input type="text" id="TxtSalary" name="Salary" value="" /><br />
  16:              <input type="submit" name="BtnSave" value="Save Employee" />
  17:              <input type="button" name="BtnReset" value="Reset" />
  18:           </form>
  19:        </div>
  20:      </body>
  21:  </html>

3. 创建Index View的链接

打开 Index.cshtml 文件,添加指向 AddNew action方法的链接

   1:  <ahref="/Employee/AddNew">Add New</a>

4. 运行

关于实验9

使用Form 标签的作用是什么?

在系列文章第一讲中,我们已经知道,Web编程模式不是事件驱动的编程模式,是请求响应模式。最终用户会产生发送请求。Form标签是HTML中产生请求的一种方式,Form标签内部的提交按钮只要一被点击,请求会被发送到相关的action 属性。

Form标签中方法属性是什么?

方法属性决定了请求类型。有四种请求类型:get,post,put以及delete.

  • Get: 当需要获取数据时使用。
  • Post: 当需要新建一些事物时使用。
  • Put: 当需要更新数据时使用。
  • Delete:需要删除数据时使用。

使用Form 标签来生成请求,与通过浏览器地址栏或超链接来生成请求,有什么区别?

使用Form标签生成请求时,所有有关输入的控件值会随着请求一起发送。

输入的值是怎样发送到服务器端的?

当请求类型是Get,Put或Delete时,值会通过查询语句发送,当请求是Post类型,值会通过Post数据传送。

使用输入控件名的作用是什么?

所有输入控件的值将随着请求一起发送。同一时间可能会接收到多个值,为了区分发送到所有值为每个值附加一个Key,这个Key在这里就是名称属性。

名称和 Id的作用是否相同?

不相同,名称属性是HTML内部使用的,当请求被发送时,然而 ID属性是在JavaScript中开发人员为了实现一些动态功能而调用的。

“input type=submit” 和 “input type=button”的区别是什么?

提交按钮在给服务器发送请求而专门使用的,而简单的按钮是执行一些自定义的客户端行为而使用的。按钮不会自己做任何事情。

实验10——在服务器端(或Controller)获取Post数据

1. 创建 SaveEmployee  action 方法

在 Employee控制器中创建 名为 ”SaveEmployee“ action 方法:

   1:  public string SaveEmployee(Employee e)
   2:  {
   3:     return e.FirstName + "|"+ e.LastName+"|"+e.Salary;
   4:  }

2. 运行

关于实验10

action 方法内部的Textbox 值是如何更新 Employee 对象的?

在 Asp.Net MVC中有个 Model Binder的概念:

  • 无论请求是否由带参的action方法生成,Model Binder都会自动执行。
  • Model Binder会通过方法的元参数迭代,然后会和接收到参数名称做对比。如果匹配,则响应接收的数据,并分配给参数。
  • 在Model Binder迭代完成之后,将类参数的每个属性名称与接收的数据做对比,如果匹配,则响应接收的数据,并分配给参数。

如果两个参数是相关联的会发生什么状况,如参数”Employee e“和 “string FirstName”?

FirstName会被元 First Name变量和 e.FirstName 属性更新。

Model Binder是组合的关系吗?

是,在实验 9 中都是根据控件名称执行的。

例如:

Customer 类和 Address 类:

   1:  public class Customer
   2:  {
   3:      public string FName{get;set;}
   4:      public Address address{get;set;}
   5:  }
   6:  public class Address
   7:  {
   8:      public string CityName{get;set;}
   9:      public string StateName{get;set;}
  10:  }

Html 代码

   1:  ...
   2:  ...
   3:  ...
   4:  <input type="text" name="FName">
   5:  <input type="text" name="address.CityName">
   6:  <input type="text" name="address.StateName">
   7:  ...
   8:  ...
   9:  ...

实验11——重置按钮和取消按钮

1. 添加重置和取消按钮

   1:  ...
   2:   
   3:  ...
   4:   
   5:  ...
   6:   
   7:  <input type="submit" name="BtnSubmit” value="Save Employee" />
   8:   
   9:  <input type="button" name="BtnReset" value="Reset" onclick="ResetForm();" />
  10:   
  11:  <input type="submit" name="BtnSubmit" value="Cancel" />

2. 定义 ResetForm 函数 

在Html的头部分添加脚本标签,并编写JavaScript 函数 命名为”ResetForm“如下:

   1:  <script>
   2:      function ResetForm() {
   3:          document.getElementById('TxtFName').value = "";
   4:          document.getElementById('TxtLName').value = "";
   5:          document.getElementById('TxtSalary').value = "";
   6:      }
   7:  </script>

3. 在 EmplyeeController SaveEmployee 方法中实现取消按钮的点击功能

修改SaveEmployee  方法:

   1:  public ActionResult SaveEmployee(Employee e, string BtnSubmit)
   2:  {
   3:      switch (BtnSubmit)
   4:      {
   5:          case "Save Employee":
   6:              return Content(e.FirstName + "|" + e.LastName + "|" + e.Salary);
   7:          case "Cancel":
   8:              return RedirectToAction("Index");
   9:      }
  10:      return new EmptyResult();
  11:  }

4.  运行

5. 测试重置功能

6. 测试保存和取消功能

关于实验11

在实验11中为什么将保存和取消按钮设置为同名?

在日常使用中,点击提交按钮之后,请求会被发送到服务器端,所有输入控件的值都将被发送。提交按钮也是输入按钮的一种。因此提交按钮的值也会被发送。

当保存按钮被点击时,保存按钮的值也会随着请求被发送到服务器端,当点击取消按钮时,取消按钮的值”取消“会随着请求发送。

在Action 方法中,Model Binder 将维护这些工作。会根据接收到的值更新参数值。

实现多重提交按钮有没有其他可用的方法?

事实上,有很多可实现的方法。以下会介绍三种方法。

1. 隐藏 Form 元素

  •    在View中创建一个隐藏form元素
   1:  <form action="/Employee/CancelSave" id="CancelForm" method="get" style="display:none">
   2:   
   3:  </form>
  •    将提交按钮改为正常按钮,并且使用JavaScript脚本代码:
   1:  <input type="button" name="BtnSubmit" value="Cancel" onclick="document.getElementById('CancelForm').submit()" />

2. 使用JavaScript 动态的修改URL

   1:  <form action="" method="post" id="EmployeeForm" >
   2:  ...
   3:  ...
   4:  <input type="submit" name="BtnSubmit" value="Save Employee" onclick="document.getElementById('EmployeeForm').action = '/Employee/SaveEmployee'" />
   5:  ...
   6:  <input type="submit" name="BtnSubmit" value="Cancel" onclick="document.getElementById('EmployeeForm').action = '/Employee/CancelSave'" />
   7:  </form>

3. Ajax

使用常规输入按钮来代替提交按钮,并且点击时使用jQuery或任何其他库来产生纯Ajax请求。

为什么在实现重置功能时,不使用 input type=reset ?

因为输入类型type=reset 不是清晰的值,仅设置了控件的默认值。如:

   1:  <input type="text" name="FName" value="Sukesh">

在该实例中控件值为:Sukesh,如果使用type=reset来实现重置功能,当重置按钮被点击时,textbox的值会被设置为”Sukesh“。

如果控件名称与类属性名称不匹配会发生什么情况?

首先来看一段HTML代码:

   1:  First Name: <input type="text" id="TxtFName" name="FName" value="" /><br />
   2:  Last Name: <input type="text" id="TxtLName" name="LName" value="" /><br />
   3:  Salary: <input type="text" id="TxtSalary" name="Salary" value="" /><br />

Model 类包含属性名称如FirstName, LastName 和 Salary。由于默认的Model Binder在该片段内不会发生作用。

我们会给出三种解决方案

  • 内部action 方法,获取请求中的post数据。Form 语法和手动构建Model对象:
   1:  public ActionResult SaveEmployee()
   2:  {
   3:          Employee e = new Employee();
   4:          e.FirstName = Request.Form["FName"];
   5:          e.LastName = Request.Form["LName"];
   6:          e.Salary = int.Parse(Request.Form["Salary"])
   7:  ...
   8:  ...
   9:  }
  • 使用参数名称和手动创建Model对象:
   1:  public ActionResult SaveEmployee(string FName, string LName, int Salary)
   2:  {
   3:      Employee e = new Employee();
   4:      e.FirstName = FName;
   5:      e.LastName = LName;
   6:      e.Salary = Salary;
   7:  ...
   8:  ...
   9:  }
  • 创建自定义 Model Binder ,代替默认的Model Binder:

1. 创建自定义Model Binder

   1:  public class MyEmployeeModelBinder : DefaultModelBinder
   2:  {
   3:      protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
   4:      {
   5:          Employee e = new Employee();
   6:          e.FirstName = controllerContext.RequestContext.HttpContext.Request.Form["FName"];
   7:          e.LastName = controllerContext.RequestContext.HttpContext.Request.Form["LName"];
   8:          e.Salary = int.Parse(controllerContext.RequestContext.HttpContext.Request.Form["Salary"]);
   9:          return e;
  10:      }
  11:  }

2. 替换默认的 Model Binder

   1:  public ActionResult SaveEmployee([ModelBinder(typeof(MyEmployeeModelBinder))]Employee e, string BtnSubmit)
   2:  {
   3:      ......

RedirectToAction 函数的功能?

RedirectToAction 生成 RedirectToRouteResult 如ViewResult 和 ContentResult,RedirectToRouteResult是 ActionResult的孩子节点,表示间接响应,当浏览器接收到RedirectToRouteResult,新Action 方法产生新的请求。

EmptyResult是什么?

是ActionResult的一个孩子节点,当浏览器接收到 EmptyResult,作为响应,它会显示空白屏幕,表示无结果。在本实验中不会发生EmptyResult。

实验12——保存数据库记录,更新表格

1. 在EmployeeBusinessLayer  中创建 SaveEmployee,如下:

   1:  public Employee SaveEmployee(Employee e)
   2:  {
   3:      SalesERPDAL salesDal = new SalesERPDAL();
   4:      salesDal.Employees.Add(e);
   5:      salesDal.SaveChanges();
   6:      return e;
   7:  }

2. 修改 SaveEmployee 的Action 方法

在 EmployeeController 中修改 SaveEmployee ation方法 代码如下:

   1:  public ActionResult SaveEmployee(Employee e, string BtnSubmit)
   2:  {
   3:      switch (BtnSubmit)
   4:      {
   5:          case "Save Employee":
   6:              EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();
   7:              empBal.SaveEmployee(e);
   8:              return RedirectToAction("Index");
   9:          case "Cancel":
  10:              return RedirectToAction("Index");
  11:      }
  12:      return new EmptyResult();
  13:  }

3.运行

实验 13——添加服务器端验证

在实验10中已经了解了Model Binder的基本功能,再来了解一下:

  • Model Binder使用 post数据更新 Employee对象
  • 但是这不仅仅执行Model Binder的。Model Binder需要更新Model State。Model State封装了 Model状态。
  • ModelState包含属性IsValid ,该属性表示 Model 是否成功更新。如果任何服务器端验证失败,Model将不更新

              ModelState保存验证错误的详情。

               如:ModelState[“FirstName”],表示将包含所有与First Name相关的错误。

              保存接收的值(Post 数据或查询字符串的值)

             在Asp.net MVC,将使用 DataAnnotations来执行服务器端的验证。

在我们了解Data Annotation之前先来了解一些Model Binder知识:

使用元数据类型时,Model Binder 是如何工作的?

当Action方法包含元类型参数,Model Binder会与参数名称对比。

  • 当匹配成功时,响应接收的数据会被分配给参数。
  • 匹配不成功时,参数会设置为缺省值,例如,如果是字符串类型则被设置为null,如果是整型则设置为0.
  • 由于数据类型未匹配异常的抛出,不会进行值分配。

当参数是类时,Model Binder 是如何工作的?

当参数为类,Model Binder将通过检索类所有的属性,将接收的数据与类属性名称比较。

当匹配成功时:

如果接收的值是空,则会将空值分配给属性,如果无法执行空值分配,会设置缺省值,ModelState.IsValid将设置为fasle。

如果空值分配成功,会考虑值是否合法,ModelState.IsValid将设置为fasle。

如果匹配不成功,参数会被设置为缺省值。在本实验中ModelState.IsValid不会受影响。

1. 使用 DataAnnotations 装饰属性

   1:  public class Employee
   2:  {
   3:  ...
   4:  ...
   5:      [Required(ErrorMessage="Enter First Name")]
   6:      public string FirstName { get; set; }
   7:   
   8:      [StringLength(5,ErrorMessage="Last Name length should not be greater than 5")]
   9:      public string LastName { get; set; }
  10:  ...
  11:  ...
  12:  }

2.  修改  SaveEmployee 方法

   1:  public ActionResult SaveEmployee(Employee e, string BtnSubmit)
   2:  {
   3:      switch (BtnSubmit)
   4:      {
   5:          case "Save Employee":
   6:              if (ModelState.IsValid)
   7:              {
   8:                  EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();
   9:                  empBal.SaveEmployee(e);
  10:                  return RedirectToAction("Index");
  11:              }
  12:              else
  13:              {
  14:                  return View("CreateEmployee ");
  15:              }
  16:          case "Cancel":
  17:              return RedirectToAction("Index");
  18:      }
  19:      return new EmptyResult();
  20:  }

3. 在View中显示错误,修改 Views/Index/CreateEmployee.cshtml 代码,使用Table标签如下:

   1:  <table>
   2:     <tr>
   3:        <td>
   4:           First Name:
   5:        </td>
   6:        <td>
   7:           <input type="text" id="TxtFName" name="FirstName" value="" />
   8:        </td>
   9:     </tr>
  10:     <tr>
  11:        <td colspan="2" align="right">
  12:          @Html.ValidationMessage("FirstName")
  13:        </td>
  14:     </tr>
  15:     <tr>
  16:        <td>
  17:          Last Name:
  18:        </td>
  19:        <td>
  20:           <input type="text" id="TxtLName" name="LastName" value="" />
  21:        </td>
  22:     </tr>
  23:     <tr>
  24:        <td colspan="2" align="right">
  25:           @Html.ValidationMessage("LastName")
  26:        </td>
  27:     </tr>
  28:   
  29:     <tr>
  30:        <td>
  31:          Salary:
  32:        </td>
  33:        <td>
  34:           <input type="text" id="TxtSalary" name="Salary" value="" />
  35:        </td>
  36:     </tr>
  37:     <tr>
  38:        <td colspan="2" align="right">
  39:          @Html.ValidationMessage("Salary")
  40:        </td>
  41:     </tr>
  42:   
  43:     <tr>
  44:        <td colspan="2">
  45:           <input type="submit" name="BtnSubmit" value="Save Employee" />
  46:           <input type="submit" name="BtnSubmit" value="Cancel" />
  47:           <input type="button" name="BtnReset" value="Reset" onclick="ResetForm();" />
  48:        </td>
  49:     </tr>
  50:  </table>

4. 运行测试

导航到“Employee/AddNew” 方法,执行测试。

测试1。

测试2

注意:可能会出现以下错误:

“The model backing the 'SalesERPDAL' context has changed since the database was created. Consider using Code First Migrations to update the database.”

为了解决上述错误,在Global.asax文件中在 Application_Start后添加以下语句:

   1:  Database.SetInitializer(new DropCreateDatabaseIfModelChanges<SalesERPDAL>());

注意: 使用Database类需要引用 “System.Data.Entity”命名空间

关于实验13

@Html.ValidationMessage是什么意思?

  • @符号表示是Razor代码
  • Html是HtmlHelper类的实例。
  • ValidationMessage是HtmlHelper类的函数,用来表示错误信息。

ValidationMessage 函数是如何工作的?

ValidationMessage 是运行时执行的函数。如之前讨论的,ModelBinder更新ModelState。ValidationMessage根据关键字显示ModelState表示的错误信息。

如果我们需要可空的整数域,该怎么做?

   1:  public int? Salary{get;set;}

UpdateModel 和 TryUpdateModel 方法之间的区别是什么?

TryUpdateModel 与UpdateModel 几乎是相同的,有点略微差别。

如果Model调整失败,UpdateModel会抛出异常。就不会使用UpdateModel的 ModelState.IsValid属性。

TryUpdateModel是将函数参数与Employee对象保持相同,如果更新失败,ModelState.IsValid会设置为False值。

客户端验证是什么?

客户端验证是手动执行的,除非使用HTML 帮助类。我们将在下一节介绍HTML 帮助类。

实验14——自定义服务器端验证

1. 创建自定义验证

新建类,并命名为FirstNameValidation,代码如下:

   1:  public class FirstNameValidation:ValidationAttribute
   2:  {
   3:      protected override ValidationResult IsValid(object value, ValidationContext validationContext)
   4:      {
   5:          if (value == null) // Checking for Empty Value
   6:          {
   7:              return new ValidationResult("Please Provide First Name");
   8:          }
   9:          else
  10:          {
  11:              if (value.ToString().Contains("@"))
  12:              {
  13:                  return new ValidationResult("First Name should contain @");
  14:              }
  15:          }
  16:          return ValidationResult.Success;
  17:      }
  18:  }

2. 附加到First Name

打开Employee类,删除FirstName的默认的Required属性,添加FirstNameValidation,代码如下:

   1:  [FirstNameValidation]
   2:  public string FirstName { get; set; }

3. 运行

导航到Employee/AddNew

测试1:

测试2:

结论

本节主要讲解了数据访问层相关的知识,如数据验证,数据更新,数据处理,form表单的使用等。

在下一章,我们主要讲述以下内容:

  • 实现客户端验证
  • 理解HTML 帮助类
  • 实现认证功能
  • 给部分View添加页脚
  • 使用母版页创建统一的布局
  • 自定义请求过滤器                   

数据处理是MVC学习中比较重要的部分,在完成本节学习的同时,你是否对MVC的理解又进了一步?

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏祝威廉

Kafka Zero-Copy 使用分析

Kafka 我个人感觉是性能优化的典范。而且使用Scala开发,代码写的也很漂亮的。重点我觉得有四个

2072
来自专栏我和PYTHON有个约会

Django来敲门~第一部分【5.1.项目配置settings.py详解】

我们创建好了一个Python项目(mysite/)之后,需要在项目中添加模块应用(polls/),在模块应用中添加处理功能逻辑,如添加模块中的视图处理函数(po...

1073
来自专栏Golang语言社区

深入学习Golang—channel

Channel 1. 概述 “网络,并发”是Go语言的两大feature。Go语言号称“互联网的C语言”,与使用传统的C语言相比,写一个Server所使用的代码...

5379
来自专栏逆向技术

x64内核HOOK技术之拦截进程.拦截线程.拦截模块

            x64内核HOOK技术之拦截进程.拦截线程.拦截模块 一丶为什么讲解HOOK技术. 在32系统下, 例如我们要HOOK SSDT表,那么...

5057
来自专栏大内老A

WCF技术剖析之一:通过一个ASP.NET程序模拟WCF基础架构

细算起来,已经有好几个月没有真正的写过文章了。近半年以来,一直忙于我的第一本WCF专著《WCF技术剖析》的写作,一直无暇管理自己的Blog。到目前为止《WCF技...

2777
来自专栏向治洪

JSBridge深度剖析

概述 做过混合开发的人都知道Ionic和PhoneGap之类的框架,这些框架在web基础上包装一层Native,然后通过Bridge技术的js调用本地的库。 在...

3445
来自专栏菩提树下的杨过

Oracle中使用Entity Framework 6.x Code-First方式开发

去年写过一篇EF的简单学习笔记,当时EF还不支持Oracle的Code-First开发模式,今天无意又看了下Oracle官网,发现EF6.X已经支持了,并且给出...

2635
来自专栏xingoo, 一个梦想做发明家的程序员

Oozie分布式任务的工作流——脚本篇

继前一篇大体上翻译了Email的Action配置,本篇继续看一下Shell的相关配置。 Shell Action Shell Action可以执行Shel...

2519
来自专栏腾讯云API

【转】腾讯云 TCCLI 实践分享

原文地址:https://cloud.tencent.com/developer/article/1158013

1813
来自专栏Flutter入门

Flutter入门三部曲(3) - 数据传递/状态管理

这个既熟悉又陌生类可以帮助我们在Flutter中沿着树向下传递信息。这个类只是简单的保存了一个状态而已。

2030

扫码关注云+社区

领取腾讯云代金券