7 天玩转 ASP.NET MVC — 第 3 天

目录

0. 前言

咱们假定你在开始学习时已经阅读了前两天的学习内容。在第 2 天咱们完成了关于显示 Employees 列表的项目。html

在第三天,咱们将会经过介绍数据访问层和数据入口将它升级到一个新的层次。面试

1. 数据访问层

在真实场景的项目中,若是没有 Database,那么这个项目是未完成的。在咱们的项目中,咱们尚未谈到数据库。第三天的首个 Lab 将会学习数据库和数据库层。数据库

这里咱们将使用 SQL Server 和 Entity Framework 来建立 Database 和 Database 访问层。编程

简单来讲,什么是 Entity Framework?

这是一个 ORM 工具。ORM 表明的是 Object Relational Mapping。即:对象关系映射。浏览器

在 RDBMS 领域中,咱们所谈论的 Tables 表格和 Columns 列的这些方面,在 .NET 领域(面向对象领域)中被称为 Classes 类,对象和属性。服务器

当咱们思考任何有关数据驱动应用的方式时,均可以得出如下两种方式:mvc

  • 书写代码来和数据库打交道(被称为数据访问层和数据库逻辑)app

  • 书写代码来将数据库数据映射到面向对象中,反之亦然。ide

ORM 是一个工具,能够自动作如上两件事。Entity Framework 是微软的 ORM 工具。函数

什么是 Code First 方法?

在 Entity Framework 中,咱们可使用以下三种的任意方法:

  • Database First 方法。建立一个有表,列和关系的数据库。Entity Framework 将会生成对应的 Model 类(业务实体)和数据访问层代码。

  • Model First 方法。在这个方法中,Model 类和它们之间的联系将会被 Model 设计者在 Visual Studio 中被手动定义。而后 Entity Framework 会自动建立数据访问层和拥有表、列以及关系的数据库。

  • Code First 方法。在这个方法中,手动建立 POCO 类。这些类中的关系将会被代码所定义。当应用第一次执行时,Entity Framework 将会自动在数据库服务器上建立数据访问层和拥有表、列以及关系的数据库。

什么是 POCO 类?

POCO 表明的是「Plain Old CLR Objects」。POCO 类表明的是咱们所建立的简单 .NET 类。在咱们以前的例子中, Employee 类是一个简单的 POCO。

2. Lab 8 — 向项目中添加数据访问层

第一步:建立数据库

链接 SQL Server 而后建立一个新的数据库,命名为「SalesERPDB」。

7 天玩转 ASP.NET MVC — 第 3 天

第二步:建立 ConnectionString

打开 Web.config 文件,而后在 Configuration 区域内添加以下片断:

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

第三步:添加 Entity Framework 引用

右击项目-> 管理 Nuget 包。搜索 Entity Framework,而后点击安装。

7 天玩转 ASP.NET MVC — 第 3 天

第四步:建立数据访问层

  • 在根目录下建立一个新文件夹,命名为「DataAccessLayer」,而后在里面建立一个新的类,命名为「SalesERPDAL」。

  • 在类顶部写引用声明以下 using System.Data.Entity;

  • 继承 DbContext 的类「SalesERPDAL」

    public class SalesERPDAL: DbContext { }

第五步:为 Employee 类建立主键

打开 Employee 类并在类顶部声明以下:

using System.ComponentModel.DataAnnotations;

在 Employee 类中添加 EmployeeId 属性,而后将其标注为 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; }
}

第六步:定义映射

在「SalesERPDAL」类中添加以下声明语句:

using WebApplication1.Models;

在 SalesERPDAL 类中重写 OnModelCreating 方法。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
	modelBuilder.Entity<employee>().ToTable("TblEmployee");
	base.OnModelCreating(modelBuilder);
}

注意:上述代码中的片断「TblEmployee」表明的是表名。在运行时讲自动被建立。

第七步:在数据库中建立 Employees 属性

在「SalesERPDAL」类中建立一个新属性,命名为 Employee,以下所示:

public DbSet<employee> Employees{get;set;}

DbSet 将会展现全部能够在数据库中查询到的 Employees。

第八步:改变业务层代码,从数据库中读取数据

打开 EmployeeBusinessLayer 类,在顶部加上声明以下:

using WebApplication1.DataAccessLayer;

如今改变 GetEmployees 方法以下:

public List<employee> GetEmployees()
{
	SalesERPDAL salesDal = new SalesERPDAL();
	return salesDal.Employees.ToList();
}

第九步:执行并测试

按下 F5,并执行应用。

7 天玩转 ASP.NET MVC — 第 3 天

如今的数据库中,咱们没有任何的 Employees,因此咱们看见的是一个空白的 Grid。

查看数据库,如今咱们能够在 TblEmployee 表中看到全部的列。

7 天玩转 ASP.NET MVC — 第 3 天

第十步:插入测试数据

向 TblEmployee 表中插入一些测试数据。

7 天玩转 ASP.NET MVC — 第 3 天

第十一步:执行并测试应用

按下 F5 并再次运行应用。

7 天玩转 ASP.NET MVC — 第 3 天

Lab 8 的 Q&A

什么是 DbSet?

DbSet 简单地表示了能够从数据库中查询到的实体集合。当咱们再次写一个 Linq 查询时,DbSet 对象会对查询进行内存转换,而后触发数据库。

在咱们的例子中,「Employee」是一个 DbSet,它承载了全部能够从数据库中查询到的 Employee 实体对象。每一次咱们尝试访问「Employees」时,它都将从“TblEmployee”表中获取记录,而后将其转换为「Employees」对象并返回集合。

数据库链接串和数据访问层是如何链接的?

Mapping 经过名称来实现。在咱们的例子中,ConnectionString 名称和数据访问层类的名称是同样的,即「SalesERPDAL」,所以它们是自动映射的。

咱们能够更改 ConnectionString 的名称吗?

答案是确定的。在这个例子中,咱们须要在数据访问层类中定义一个构造函数以下:

public SalesERPDAL():base("NewName")
{
}

3. 组织全部

咱们须要作几个改变,使得全部是有组织和有意义的。

第一步:重命名

  • 「TestController」换名为 「EmployeeController」。

  • GetView 行为方法改成 Index。

  • Test 文件夹(Views 文件夹下) 改成 Employee

  • 「MyView」视图改成「Index」。

第二步:从 EmployeeListViewModel 中删除 UserName 属性

第三步:从视图中删除 UserName

打开 View/Employee.Index.cshtml 视图,而后从中删除 UserName。

简单来讲,就是删除以下代码:

Hello @Model.UserName
<hr />

第四步:在 EmployeeController 中更改 Index 行为方法

更改 EmployeeController 中的 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
}

如今执行的 URL 将会为:「…/Employee/Index」。

4. Lab 9 — 建立 Data Entry Screen

第一步:建立 Action 方法

在 EmployeeController 中建立一个 Action 方法,命名为「AddNew」,以下:

public ActionResult AddNew()
{
	return View("CreateEmployee");
}

第二步:建立 View

在文件夹 View/Employee 下建立一个 View,命名为「CreateEmployee」。代码以下:

@{
	Layout = null;
}
<!DOCTYPE html>
<html>
	<head>
  	<meta name="viewport" content="width=device-width" />
  	<title>CreateEmployee</title>
	</head>
	<body>
      <div>
     	<form action="/Employee/SaveEmployee" method="post">
        First Name: <input type="text" id="TxtFName" name="FirstName" value="" /><br />
        Last Name: <input type="text" id="TxtLName" name="LastName" value="" /><br />
        Salary: <input type="text" id="TxtSalary" name="Salary" value="" /><br />
        <input type="submit" name="BtnSave" value="Save Employee" />
        <input type="button" name="BtnReset" value="Reset" />
     	</form>
      </div>
	</body>
</html>

第三步:在 Index 视图中建立一个连接

打开 Index.cshtml,而后增长一个超连接指向 AddNew 行为的URL。

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

第四步:执行并测试应用

按下 F5 并执行应用。

7 天玩转 ASP.NET MVC — 第 3 天

Lab 9 的 Q&A

Form 标签的目的是什么?

在第一天的系列学习中,咱们已经明白了「Web 世界不会遵循事件驱动编程模型。它遵循的是请求响应模型。终端用户发出请求,而后服务器给出响应。」Form 标签是 HTML 中作出响应的其中一种方式。只要标签里的提交按钮被点击,一个请求就将发送给动做属性中指定的 URL 中。

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

它决定了请求的类型。请求也许是以下的其中一种:get、post、put 或者是 delete。

  • Get:当咱们想获取什么数据时

  • Post:当咱们想建立什么数据时

  • Put:当咱们想更新什么数据时

  • Delete:当咱们想删除什么数据时

运用 Form 标签和经过浏览器地址栏或者超连接来发出请求,有何区别?

当咱们使用 Form 标签来发送请求时,全部输入控件中的值都会伴随着请求一块儿被处理。

Checkbox、Radio 按钮和 Dropdowns 控件中的值也会被发送吗?

答案是确定的。全部输入控件(输入类型为 Text,Radio,Checkbox)以及 Dropdowns(表示的是被选中的元素)都会被发送。

输入的值如何发送给服务器?

当请求的类型是 Get、Put 或者 Delete 时,输入的值会以查询字符串参数的方式发送。

当请求的类型是 Post 时,输入的值会以 Post 数据发送。

输入控件中的 Name 属性的目的是什么?

就像咱们以前所谈论的,当按钮被点击时,输入控件中的值将会随着请求一块儿被发送。这会使得服务器在这个时刻接收到多于一个的值。为了在发送值的时候,单独区别每个值,就会为它们附加上一个 Key,这个 Key 就是「Name」属性。

Name 和 Id 属性的目的是不是相同的?

答案是否认的。就像刚才的问题所说,当请求发生时,「Name」属性被 HTML 所使用,而「Id」属性被开发者所使用,为一些 JavaScript 实现一些动态功能。

「input type = submit」 和 「input type = button」有什么区别?

当我向服务器发送请求时,Submit 按钮会被特殊用到。而一个简单的按钮是用来处理一些客户端的行为的。简单的按钮不会本身作一些事情。

5. Lab 10 — 在服务器/Controller 获取 Posted 数据

第一步:建立 SaveEmployee 行为方法

在 Employee 控制器中建立一个行为方法,命名为 SaveEmployee,代码以下:

public string SaveEmployee(Employee e)
{
   return e.FirstName + "|"+ e.LastName+"|"+e.Salary;
}

第二步:执行并测试

按下 F5 并执行应用。

7 天玩转 ASP.NET MVC — 第 3 天

Lab 10 的 Q&A

在 Action 方法里,Textbox 的值是如何更新 Employee 对象的?

在 ASP.NET MVC 中,存有一个概念,叫作 Model Binder。

  • 不管什么时候一个包含参数的请求向 Action 方法发送时,Model Binder 都会自动执行。

  • Model Binder 将会遍历方法的全部原始参数,而后将它们与发送过来的数据的参数的名称相对比。(发送过来的数据意味着要么是 Posted 数据,或者是查询字符串)。当匹配成功时,会依照发送过来的数据分配给参数。

  • 当 Model Binder 遍历完每个类参数中的每个属性后,而后和发送过来的数据作对比。当匹配成功后,依照发送过来的数据分配给参数。

当两个参数是特指的,将会发生什么?例如第一个是「Employee」,第二个是「FirstName」?

FirstName 将会在初始的变量 FirstName 中更新,也会在 e.FirstName 属性中更新。

ModelBinder 能够和组合关系一块儿运用吗?

答案是确定的。可是在这个情形下控件的名称应该被给出。例如:

Customer 和 Address 类的代码以下:

public class Customer
{
	public string FName{get;set;}
	public Address address{get;set;}
}
public class Address
{
	public string CityName{get;set;}
	public string StateName{get;set;}
}

在这种情形下,HTML 以下:

...
...
...
<input type="text" name="FName">
<input type="text" name="address.CityName">
<input type="text" name="address.StateName">
...
...
...

6. Lab 11 — 重置和取消按钮

第一步:开始重置和取消按钮

增长一个重置和取消按钮,代码以下:

...
...
...
<input type="submit" name="BtnSubmit&rdquo; value="Save Employee" />

<input type="button" name="BtnReset" value="Reset" onclick="ResetForm();" />

<input type="submit" name="BtnSubmit" value="Cancel" />

注意:保存和取消按钮都有相同的「Name」属性,即「BtnSubmit」。

第二步:定义 ResetForm 方法

在 HTML 顶部区域增长一个 Script 标签,用于建立一个 JavaScript 方法,命名为 ResetForm。代码以下:

<script>
	function ResetForm() {
    	document.getElementById('TxtFName').value = "";
    	document.getElementById('TxtLName').value = "";
    	document.getElementById('TxtSalary').value = "";
	}
</script>

第三步:在 EmployeeController 的 SaveEmployee 行为方法中实现取消点击事件。

改变 SaveEmployee 行为方法以下:

public ActionResult SaveEmployee(Employee e, string BtnSubmit)
{
	switch (BtnSubmit)
	{
    	case "Save Employee":
        	return Content(e.FirstName + "|" + e.LastName + "|" + e.Salary);
    	case "Cancel":
        	return RedirectToAction("Index");
	}
	return new EmptyResult();
}

第四步:执行应用

按下 F5 并执行应用。经过点击“Add New”连接导航到 AddNew 屏幕。

第五步:测试重置功能

7 天玩转 ASP.NET MVC — 第 3 天

第六步:测试 Save 和 Cancel 功能

7 天玩转 ASP.NET MVC — 第 3 天

Lab 11 的 Q&A

为何保存和取消按钮的名称是同样的?

咱们知道,一旦提交按钮被点击,一个请求就会被发送到服务器端。而且伴随着请求,全部输入控件的值也一块儿被发送。

Submit 按钮也是一个输入按钮。由于按钮的值也会被发送。

当保存按钮被点击时,保存按钮的值,即「Save Employee」将会随着请求一块儿被发送。当取消按钮被点击时,取消按钮的值,即「Cancel」将会随着请求一块儿被发送。

在 Action 方法中。Model Binder 将会处理这些工做。它将会依照输入的值(伴随着请求)更新参数的值。

实现多个提交按钮的方式是什么?

这里有多个方式。我介绍其中三种。

  • 隐藏 Form 元素

第一步:在视图中建立一个隐藏 Form 元素

<form action="/Employee/CancelSave" id="CancelForm" method="get" style="display:none">
</form>

第二步:改变 Submit 按钮为一个常规按钮,而且经过 JavaScript 将上面的 Form 发送

<input type="button" name="BtnSubmit" value="Cancel" onclick="document.getElementById('CancelForm').submit()" />
  • 运用 JavaScript 动态地改变更做 URL

    <form action="" method="post" id="EmployeeForm" > ... ... <input type="submit" name="BtnSubmit" value="Save Employee" onclick="document.getElementById('EmployeeForm').action = '/Employee/SaveEmployee'" /> ... <input type="submit" name="BtnSubmit" value="Cancel" onclick="document.getElementById('EmployeeForm').action = '/Employee/CancelSave'" /> </form>

  • Ajax

再也不运用 Submit 按钮,取而代之的是简单的输入按钮,而后运用 JQuery 或者其它库来实现纯 Ajxa 请求。

为何咱们在实现重置功能时,没使用「input type = reset」?

「input type = reset」控件不会清除值,它只是将控件的值改成默认的值。例如:

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

在这个例子中,控件的默认值是「Sukesh」。

若是咱们运用「input type = reset」来实现重置功能,那么每一次点击重置按钮,默认的值「Sukesh」将会被设置到 Textbox 中。

当名称没有与类中的属性名称匹配时,会怎样?

这是一个在面试中常常被问到的常规问题。

例如咱们有一段 HTML 代码以下:

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

如今咱们的 Model 类包含的属性名称有 FirstName,LastName 和 Salary。所以默认的 Model Binder 将不会在这里处理。

在这种情形下,咱们有三种解决方案:

  • 在 Action 方法内部,运用 Request.Form 语法来检索发送过来的值,而后手动构造 Model 对象以下:

    public ActionResult SaveEmployee() { Employee e = new Employee(); e.FirstName = Request.Form["FName"]; e.LastName = Request.Form["LName"]; e.Salary = int.Parse(Request.Form["Salary"]) ... ... }

  • 运用参数名称,而后手动建立 Model 对象以下:

    public ActionResult SaveEmployee(string FName, string LName, int Salary) { Employee e = new Employee(); e.FirstName = FName; e.LastName = LName; e.Salary = Salary; ... ... }

  • 建立自定义的 Model Binder 来替换默认的 Model Binder。

第一步:建立自定义的 Model Binder

public class MyEmployeeModelBinder : DefaultModelBinder
{
	protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
	{
    	Employee e = new Employee();
    	e.FirstName = controllerContext.RequestContext.HttpContext.Request.Form["FName"];
    	e.LastName = controllerContext.RequestContext.HttpContext.Request.Form["LName"];
    	e.Salary = int.Parse(controllerContext.RequestContext.HttpContext.Request.Form["Salary"]);
    	return e;
	}
}

第二步:用这个新的 Model Binder 来替换默认的 Model Binder

public ActionResult SaveEmployee([ModelBinder(typeof(MyEmployeeModelBinder))]Employee e, string BtnSubmit)
{
	......
}

RedirectToFunction 函数是作什么的?

它用来产生 RedirectToRouteResult,就像 ViewResult 和 ContentResult同样(在第一天学习中探讨)。RedirectToRouteResult 是 ActionResult 的子类,它表明的是间接的响应。当浏览器接到 RedirectToRouteResult,它就会产生新的请求到一个新的行为方法。

注:这里浏览器对新的请求是有责任的,所以 URL 将会更新到一个新的 URL。

什么是 EmptyResult?

它是 ActionResult 的其中一个子类。当浏览器接到的响应是 EmptyResult 时,它将会简单地呈现一个空白屏幕。它简单地表明「No Result」。

在咱们的例子中,这种情形不会发生。只要确保全部的代码路径返回的值。

注:当 Action 方法返回的值是空的,结果等同于 EmptyResult。

7. Lab 12 — 在数据库中保存记录并更新 Grid

第一步:在 EmployeeBusinessLayer 中建立 SaveEmployee

public Employee SaveEmployee(Employee e)
{
	SalesERPDAL salesDal = new SalesERPDAL();
	salesDal.Employees.Add(e);
	salesDal.SaveChanges();
	return e;
}

第二步:改变 SaveEmployee 行为方法

在 EmployeeController 中,改变 SaveEmployee 行为方法,代码以下:

public ActionResult SaveEmployee(Employee e, string BtnSubmit)
{
	switch (BtnSubmit)
	{
    	case "Save Employee":
        	EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();
        	empBal.SaveEmployee(e);
        	return RedirectToAction("Index");
    	case "Cancel":
        	return RedirectToAction("Index");
	}
	return new EmptyResult();
}

第三步:执行并测试

按下 F5 并执行应用。导航到 Data 入口屏幕并输入一些合法的值。

7 天玩转 ASP.NET MVC — 第 3 天

8. Lab 13 — 增长服务器端认证

在 Lab 10 中,咱们已经了解了 Model Binder 的基本功能。如今咱们来更多地了解下。

  • Model Binder 经过发送过来的数据来更新 Employee 对象。

  • 可是这个不是 Model Binder 的惟一功能。Model Binder 还更新 ModelState。

  • 它有一个属性,称为 IsValid,这个决定了 Model(即 Employee 对象)是否更新成功了。若是服务器端的认证失败了,Model 将不会更新。

  • 它承载了认证错误。例如:ModelState["FirstName"].Errors 包含了与 First Name 相关的错误。

  • 它承载了发送过来的数据值。(Posted 数据或者是查询字符串数据)

在 ASP.NET MVC 中,咱们运用 DataAnnotations 来实现服务器端的认证。

在了解 Data Annotation 以前,咱们先了解一些 Model Binder。

ModelBinder 如何处理初始数据类型?

当 Action 方法包含初始类型参数时,Model Binder 将会把参数的名称与发送过来的数据进行对比。(发送过来的数据是 Posted 数据或者是查询字符串)

  • 当匹配成功时,将会依照发送过来的数据分配给参数。

  • 当匹配失败时,参数将会被分配给默认值。(对于整型的默认值是0,对于字符串的默认值是 null)

  • 当数据类型不匹配的异常被抛出时,这种状况下不会进行分配操做。

Model Binder 如何处理类?

当参数是一个类参数,Model Binder 将会遍历全部类的全部属性,而且将每个属性名称与发送过来的数据作对比。

  • 当匹配成功时,若是发送过来的数据是空的。

Null 值将会被分配给属性。若是不能分配,默认的值将会被设置,而且 ModelState.IsValid 将会被设置为 false。

当 Null 值能够分配给属性时,这将会被视做不合法的值,由于属性附上了认证,所以 ModelState.IsValid 将会被设置为 false。

  • 当匹配成功时,发送过来的数据不为空。

当数据类型不匹配时,将不会分配值。或者服务器端的认证失败,将分配 Null 值。此时 ModelState.IsValid 将会被设置为 false。若是不能分配 Null 值,默认的值将会被设置。

  • 当匹配不成功时,参数将会被分配为默认值。(对于整型的默认值是0,对于字符串的默认值是 null)。在这种情形下,ModelState.IsValid 将不会受到影响。

如今让咱们了解一下如何向项目中增长认证功能。

第一步:运用 DataAnnotations 装饰属性。

在 Model 文件夹下打开 Employee 类,运用 DataAnnotation 来装饰 FirstName 和 LastName,代码以下:

public class Employee
{
...
...
	[Required(ErrorMessage="Enter First Name")]
	public string FirstName { get; set; }

	[StringLength(5,ErrorMessage="Last Name length should not be greater than 5")]
	public string LastName { get; set; }
...
...
}

第二步:改变 SaveEmployee 行为方法。

打开 EmployeeController,改变 SaveEmloyee 行为方法以下:

public ActionResult SaveEmployee(Employee e, string BtnSubmit)
{
	switch (BtnSubmit)
	{
    	case "Save Employee":
        	if (ModelState.IsValid)
        	{
            	EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();
            	empBal.SaveEmployee(e);
            	return RedirectToAction("Index");
        	}
        	else
        	{
            	return View("CreateEmployee ");
        	}
    	case "Cancel":
        	return RedirectToAction("Index");
	}
	return new EmptyResult();
}

注:正如你所看见的,当 SaveEmployee 按钮点击后, ModelState.IsValid 失败,ViewResult 指向「CreateEmloyee」视图。

第三步:在视图中呈现错误

改变「Views/Index/CreateEmployee.cshtml」中的代码以下。

此次咱们将会运用「Table」标签来格式化一下 UI。

<table>
   <tr>
      <td>
         First Name:
      </td>
      <td>
         <input type="text" id="TxtFName" name="FirstName" value="" />
      </td>
   </tr>
   <tr>
      <td colspan="2" align="right">
        @Html.ValidationMessage("FirstName")
      </td>
   </tr>
   <tr>
      <td>
        Last Name:
      </td>
      <td>
         <input type="text" id="TxtLName" name="LastName" value="" />
      </td>
   </tr>
   <tr>
      <td colspan="2" align="right">
         @Html.ValidationMessage("LastName")
      </td>
   </tr>

   <tr>
      <td>
        Salary:
      </td>
      <td>
         <input type="text" id="TxtSalary" name="Salary" value="" />
      </td>
   </tr>
   <tr>
      <td colspan="2" align="right">
        @Html.ValidationMessage("Salary")
      </td>
   </tr>

   <tr>
      <td colspan="2">
        <input type="submit" name="BtnSubmit" value="Save Employee" />
        <input type="submit" name="BtnSubmit" value="Cancel" />
         <input type="button" name="BtnReset" value="Reset" onclick="ResetForm();" />
      </td>
   </tr>
</table>

第四步:执行并测试

按下 F5 并执行应用。导航到「Employee/AddNew」行为方法,并测试应用。

  • Test 1

7 天玩转 ASP.NET MVC — 第 3 天

  • Test 2

7 天玩转 ASP.NET MVC — 第 3 天

注:你也许会遇到以下错误。

「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 中添加以下声明:

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

Database 类在命名空间 System.Data.Entity 中。

Lab 13 的 Q&A

@Html.ValidationMessage 是作什么事情的?

  • @ 意味着是 Razor 代码。

  • Html 是 视图中的 HtmlHelper 类的实例。

  • ValidationMessage 是 HtmlHelper 类的方法,用于呈现错误信息。

ValidationMessage 函数如何工做的?

ValidationMessage 是一个函数。它在运行时执行。就像咱们以前所探讨的,ModelBinder 更新 ModelState。ValidationMessage 根据 Key 值来从 ModelState 中获取错误信息并呈现。

例如:ValidationMessage("FirstName") 呈现有关 First Name 的错误信息。

咱们还有其它相似于 Required 和 StringLength 的属性吗?

答案是确定的。以下所示:

  • DataType。确保数据是指定的类型,例如邮箱、信用卡号、URL 等。

  • EnumDataTypeAttribute。确保在 Enumeration 中存在该值。

  • Range Attribute。确保值在一个指定的区域内。

  • Regular。认证值是不是指定的表达式。

  • Required。确保值是存在的。

  • StringLength。认证字符串中的最大和最小字符长度。

Salary 是如何认证的?

咱们并无向 Salary 属性添加 Data Annotation,可是它依然获得了认证。缘由是这样的,在更新模型的时候,Model Binder 依然考虑到了属性的数据类型。

在 Test 1 中,咱们保持 Salary 为一个空字符串。在这种情形下,由于咱们有 Model Binder,ModelState.IsValid 将会为失败的而且 ModelState 将会承载与 Salary 相关的错误认证信息,这些信息将会经过 Html.ValidationMessage("Salary") 被显示在 View 中。

在 Test 2 中,Salary 数据类型匹配失败,所以认证也是失败的。

这意味着,默认状况下,整型属性将会被强制?

答案是确定的。不只仅是整型,全部的值类型都会被强制,由于它们不能为 Null 值。

若是咱们想有一个非 Required 整型域该如何?

把它设置为 Nullable?

public int? Salary{get;set;}

如何特定为 Salary 改变认证信息?

默认状况下,认证是支持 Salary的(由于它是整数类型),不会容许咱们改变认证信息。咱们能够经过 Regular 表达式、Range 或者是 Custom Validator来一样达到这个目的。

为何当认证失败时,值会被清空?

由于这是一个新的请求。数据入口视图将会在开始被呈现,而且在呈现以后和发展视图是同样的,可是和请求视图是不同的。咱们将会在第四天的学习中来学习如何保持值不变。

咱们能够明确地让 Model Binder 来执行吗?

答案是确定的。只须要简单地从 Action 方法中移走参数。默认状况下,它将会中止运行中的默认 Model Binder。

在这种情形下,咱们能够运用 UpdateModel 函数以下:

Employee e = new Employee();
UpdateModel<employee>(e);

注:UpdateModel 不会处理原始数据类型。

UpdateModel 方法 和 TryUpdateModel 方法有什么区别?

TryUpdateModel 和 UpdateModel 是同样的,除了一个附加的优点。

当 Model 因为任意缘由适配失败时,UpdateModel 将会抛出异常。这种状况下,ModelState.IsValid 函数将不会有任何左右。

TryUpdateModel 是将 Employee 对象和函数参数保持精确地一致。若是更新失败了,ModelState.IsValid 将会为 False。

客户端的认证是如何的?

这个能够被手动完成,或者咱们能够运用 HTML Helper 类。

咱们将会在第四天的学习中探讨这两种手动的客户端认证方式,以及运用 HTML Helper 来自动客户端认证。

咱们能够为一个属性附加上多个 DataAnnotation 吗?

答案是确定的。在这种情形下,多个认证都会被触发。

9. 自定义服务器端认证

第一步:建立自定义认证

建立一个新的类,叫作 FirstNameValidation。

public class FirstNameValidation:ValidationAttribute
{
	protected override ValidationResult IsValid(object value, ValidationContext validationContext)
	{
    	if (value == null) // Checking for Empty Value
    	{
        	return new ValidationResult("Please Provide First Name");
    	}
    	else
    	{
        	if (value.ToString().Contains("@"))
        	{
            	return new ValidationResult("First Name should contain @");
        	}
    	}
    	return ValidationResult.Success;
	}
}

第二步:向 First Name 中附加认证

打开 Employee 类,而后将 FirstName 属性的默认的「Required」属性移走,附加上 FirstNameValidation。

[FirstNameValidation]
public string FirstName { get; set; }

第三步:执行并测试

按下 F5,导航到「Employee/AddNew」动做。

  • Test 1

7 天玩转 ASP.NET MVC — 第 3 天

  • Test 2

7 天玩转 ASP.NET MVC — 第 3 天

10. 总结

这里咱们完成了第三天的学习。在第四天学习中,咱们将会提高项目到一个新的版本。第四天的学习事项以下:

  • 实现客户端的认证。

  • 理解 HTML Helper。

  • 实现 Authentication。

  • 部分视图增长 Footers。

原文地址:Learn MVC Project in 7 days

本文系 OneAPM 工程师编译整理。OneAPM 是应用性能管理领域的新兴领军企业,能帮助企业用户和开发者轻松实现:缓慢的程序代码和 SQL 语句的实时抓取。想阅读更多技术文章,请访问 OneAPM 官方博客

相关文章
相关标签/搜索