咱們假定你在開始學習時已經閱讀了前兩天的學習內容。在第 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 官方博客。