咱们假定你在开始学习时已经阅读了前两天的学习内容。在第 2 天咱们完成了关于显示 Employees 列表的项目。html
在第三天,咱们将会经过介绍数据访问层和数据入口将它升级到一个新的层次。面试
在真实场景的项目中,若是没有 Database,那么这个项目是未完成的。在咱们的项目中,咱们尚未谈到数据库。第三天的首个 Lab 将会学习数据库和数据库层。数据库
这里咱们将使用 SQL Server 和 Entity Framework 来建立 Database 和 Database 访问层。编程
这是一个 ORM 工具。ORM 表明的是 Object Relational Mapping。即:对象关系映射。浏览器
在 RDBMS 领域中,咱们所谈论的 Tables 表格和 Columns 列的这些方面,在 .NET 领域(面向对象领域)中被称为 Classes 类,对象和属性。服务器
当咱们思考任何有关数据驱动应用的方式时,均可以得出如下两种方式:mvc
书写代码来和数据库打交道(被称为数据访问层和数据库逻辑)app
书写代码来将数据库数据映射到面向对象中,反之亦然。ide
ORM 是一个工具,能够自动作如上两件事。Entity Framework 是微软的 ORM 工具。函数
在 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。
第一步:建立数据库
链接 SQL Server 而后建立一个新的数据库,命名为「SalesERPDB」。
第二步:建立 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,而后点击安装。
第四步:建立数据访问层
在根目录下建立一个新文件夹,命名为「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,并执行应用。
如今的数据库中,咱们没有任何的 Employees,因此咱们看见的是一个空白的 Grid。
查看数据库,如今咱们能够在 TblEmployee 表中看到全部的列。
第十步:插入测试数据
向 TblEmployee 表中插入一些测试数据。
第十一步:执行并测试应用
按下 F5 并再次运行应用。
什么是 DbSet?
DbSet 简单地表示了能够从数据库中查询到的实体集合。当咱们再次写一个 Linq 查询时,DbSet 对象会对查询进行内存转换,而后触发数据库。
在咱们的例子中,「Employee」是一个 DbSet,它承载了全部能够从数据库中查询到的 Employee 实体对象。每一次咱们尝试访问「Employees」时,它都将从“TblEmployee”表中获取记录,而后将其转换为「Employees」对象并返回集合。
数据库链接串和数据访问层是如何链接的?
Mapping 经过名称来实现。在咱们的例子中,ConnectionString 名称和数据访问层类的名称是同样的,即「SalesERPDAL」,所以它们是自动映射的。
咱们能够更改 ConnectionString 的名称吗?
答案是确定的。在这个例子中,咱们须要在数据访问层类中定义一个构造函数以下:
public SalesERPDAL():base("NewName") { }
咱们须要作几个改变,使得全部是有组织和有意义的。
第一步:重命名
「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() { …… …… …… employeeListViewModel.Employees = empViewModels; //employeeListViewModel.UserName = "Admin";-->Remove this line -->Change1 return View("Index", employeeListViewModel);//-->Change View Name -->Change 2 }
如今执行的 URL 将会为:「…/Employee/Index」。
第一步:建立 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 并执行应用。
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 按钮会被特殊用到。而一个简单的按钮是用来处理一些客户端的行为的。简单的按钮不会本身作一些事情。
第一步:建立 SaveEmployee 行为方法
在 Employee 控制器中建立一个行为方法,命名为 SaveEmployee,代码以下:
public string SaveEmployee(Employee e) { return e.FirstName + "|"+ e.LastName+"|"+e.Salary; }
第二步:执行并测试
按下 F5 并执行应用。
在 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"> ... ... ...
第一步:开始重置和取消按钮
增长一个重置和取消按钮,代码以下:
... ... ... <input type="submit" name="BtnSubmit” 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 屏幕。
第五步:测试重置功能
第六步:测试 Save 和 Cancel 功能
为何保存和取消按钮的名称是同样的?
咱们知道,一旦提交按钮被点击,一个请求就会被发送到服务器端。而且伴随着请求,全部输入控件的值也一块儿被发送。
Submit 按钮也是一个输入按钮。由于按钮的值也会被发送。
当保存按钮被点击时,保存按钮的值,即「Save Employee」将会随着请求一块儿被发送。当取消按钮被点击时,取消按钮的值,即「Cancel」将会随着请求一块儿被发送。
在 Action 方法中。Model Binder 将会处理这些工做。它将会依照输入的值(伴随着请求)更新参数的值。
实现多个提交按钮的方式是什么?
这里有多个方式。我介绍其中三种。
第一步:在视图中建立一个隐藏 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。
第一步:在 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 入口屏幕并输入一些合法的值。
在 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。
当 Action 方法包含初始类型参数时,Model Binder 将会把参数的名称与发送过来的数据进行对比。(发送过来的数据是 Posted 数据或者是查询字符串)
当匹配成功时,将会依照发送过来的数据分配给参数。
当匹配失败时,参数将会被分配给默认值。(对于整型的默认值是0,对于字符串的默认值是 null)
当数据类型不匹配的异常被抛出时,这种状况下不会进行分配操做。
当参数是一个类参数,Model Binder 将会遍历全部类的全部属性,而且将每个属性名称与发送过来的数据作对比。
Null 值将会被分配给属性。若是不能分配,默认的值将会被设置,而且 ModelState.IsValid 将会被设置为 false。
当 Null 值能够分配给属性时,这将会被视做不合法的值,由于属性附上了认证,所以 ModelState.IsValid 将会被设置为 false。
当数据类型不匹配时,将不会分配值。或者服务器端的认证失败,将分配 Null 值。此时 ModelState.IsValid 将会被设置为 false。若是不能分配 Null 值,默认的值将会被设置。
如今让咱们了解一下如何向项目中增长认证功能。
第一步:运用 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」行为方法,并测试应用。
注:你也许会遇到以下错误。
「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 中。
@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 吗?
答案是确定的。在这种情形下,多个认证都会被触发。
第一步:建立自定义认证
建立一个新的类,叫作 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」动做。
这里咱们完成了第三天的学习。在第四天学习中,咱们将会提高项目到一个新的版本。第四天的学习事项以下:
实现客户端的认证。
理解 HTML Helper。
实现 Authentication。
部分视图增长 Footers。
原文地址:Learn MVC Project in 7 days
本文系 OneAPM 工程师编译整理。OneAPM 是应用性能管理领域的新兴领军企业,能帮助企业用户和开发者轻松实现:缓慢的程序代码和 SQL 语句的实时抓取。想阅读更多技术文章,请访问 OneAPM 官方博客。