【第二篇】ASP.NET MVC快速入門之數據註解(MVC5+EF6)

目錄

【第一篇】ASP.NET MVC快速入門之數據庫操做(MVC5+EF6)php

【第二篇】ASP.NET MVC快速入門之數據註解(MVC5+EF6)html

【第三篇】ASP.NET MVC快速入門之安全策略(MVC5+EF6)jquery

【第四篇】ASP.NET MVC快速入門之完整示例(MVC5+EF6)sql

【番外篇】ASP.NET MVC快速入門之免費jQuery控件庫(MVC5+EF6)數據庫

 

請關注三石的博客:http://cnblogs.com/sanshi瀏覽器

 

 

數據庫鏈接字符串

上一篇文章中,咱們使用MVC的模板自動生成了CRUD的所有操做,可是沒有配置數據庫鏈接字符串,那麼數據存到什麼地方了?安全

 

打開項目的App_Data目錄,你能夠發現數據庫原來在這裏:服務器

 

咱們經過VS自帶的數據庫訪問工具,來看下錶結構和其中的數據,首先找到[服務器資源管理器]面板,新增數據庫鏈接:數據庫設計

 

在添加鏈接嚮導對話框中,輸入服務器名:(LocalDb)\MSSQLLocalDB,這個是VS2015自帶的LocalDb的服務器實例名稱(若是你使用VS2013,這個名稱多是:(LocalDB)\v11.0)。數據庫選擇咱們剛剛建立的StudentDbContextide

 

原來若是沒有顯式的指定數據庫鏈接字符串,VS會使用默認的LocalDb實例,這個對應關係在Web.config中有定義:

<entityFramework>

       <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">

         <parameters>

              <parameter value="mssqllocaldb" />

         </parameters>

       </defaultConnectionFactory>

       <providers>

         <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />

       </providers>

</entityFramework>

 

 

固然咱們也能夠明確指定數據庫鏈接字符串:

<connectionStrings>

       <add name="DefaultConnection"

connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\AspNetMvc.QuickStart.Models.StudentDbContext.mdf;Initial Catalog=AspNetMvc.QuickStart.Models.StudentDbContext;Integrated Security=True"

         providerName="System.Data.SqlClient" />

</connectionStrings>

 

 

而後在代碼中引用這個數據庫鏈接字符串:

public class StudentDbContext : DbContext

{

       public StudentDbContext() : base("DefaultConnection")

       {

       }

 

       public DbSet<Student> Students { get; set; }

}

 

 

注意:若是使用的VS2013Data Source應該是(LocalDb)\v11.0,而VS2015對應的是(LocalDb)\MSSQLLocalDB

 

通過這個改變,在真正部署到MSSQL服務器時,簡單修改數據庫鏈接字符串就能夠了。

 

數據庫表結構

打開Students的表定義:

 

能夠看下EF是怎麼將Student模型映射到數據庫表結構的:

1.     模型中ID屬性的數據映射爲表的主鍵。

2.     模型中的string類型映射爲表的nvarchar(MAX)

3.     模型中的intDateTime分別映射爲表的intdatetime類型。

 

再來看下上一篇文章中添加到表中的數據:

 

若是你以前有數據庫設計的經驗,會很容易發現這個表結構的問題:

1.     NameMajor存儲字符串,通常須要限制最大長度,好比nvarchar(200)

2.     NameMajor列應該不容許爲空。

 

那麼怎麼來實現這兩個需求呢?直接修改數據庫確定是不行的!

 

數據註解

咱們應該從模型入手,還記得咱們在上一篇文章結尾說的那句話嗎,數據模型不只會影響數據庫的表結構,還會控制MVC視圖層的客戶端驗證和控制器層的服務器端驗證。

 

修改Student模型類,添加適當的數據註解:

public class Student

{

       public int ID { get; set; }

 

       [Required]

       [StringLength(200)]

       public string Name { get; set; }

 

       public int Gender { get; set; }

 

       [Required]

       [StringLength(200)]

       public string Major { get; set; }

 

       public DateTime EntranceDate { get; set; }

}

 

 

若是輸入[Required]時沒有智能感知,極可能是沒有引用相應的命名空間,VS能夠很方便的協助咱們添加:

 

這樣就會在文件頭部添加以下引用:

using System.ComponentModel.DataAnnotations;

 

 

直接運行項目(Ctrl+F5),此時咱們會看到以下的錯誤頁面:

 

相信使用EF的同窗都會遇到這個頁面,上面的提示也很明確,包含兩個層次的信息:

1.     數據庫建立以後模型改變了。

2.     可使用數據遷移來更新數據庫。

 

數據遷移(Migrations

VS[工具]菜單中,找到Nuget包管理器控制檯:

 

 

啓用數據遷移

在控制檯中輸入以下命令:Enable-Migrations

 

這時會在項目目錄中增長一個Migrations文件夾,裏面放置了兩個文件:

 

EF會經過C#代碼的方式將每一次對模型的修改保存到這個文件夾中,如今來看下生成的文件內容:

 

每一個遷移文件,都包含UpDown兩個重寫函數,分別對應於更新和回退。上面的代碼也很直白,Up函數中建立一個Students表,定義表結構並指定ID主鍵(PrimaryKey),Down函數用來回退操做,裏面簡單的刪除了Students表。

 

能夠看到,這裏的建立表操做並無使用最新的模型(Name列沒有nullable的設置),由於這是初始模型對應的表結構,EF會在數據庫中自動生成一個名爲__MigrationHistory表來跟蹤數據庫的狀態。

 

增長遷移項

增長遷移項須要咱們手工來進行,在程序包管理器控制檯中,輸入以下命令:

Add-Migration Add_Annotation_Name_Major

 

這時會在Migrations目錄下生成遷移文件,文件是以[時間+遷移名]命名的,方便查找:

201612160406415_Add_Annotation_Name_Major.cs

 

更新到數據庫

此時,數據庫還沒有改變,咱們還須要手工命令來更新數據庫:

Update-Database

 

此時,再來查看數據庫中Students的表結構:

 

Name列的數據類型和是否容許Null都已經改變了。

 

在真實的項目中,數據庫可能部署在遠程服務器中,這時咱們就不能直接在VS中經過Update-Database來更新數據庫了。

不過咱們能夠生成更新SQL腳本,而後拿到數據庫服務器上執行。生成這個SQL腳本的方法:

Update-Database   -Script

-SourceMigration: InitialCreate

-TargetMigration: Add_Annotation_Name_Major

 

來看下生成的SQL更新腳本:

 

有了這個SQL更新腳本,咱們就能夠方便的更新遠程數據庫了。

 

視圖的客戶端驗證

如今運行項目,轉到建立頁面:

能夠看到,若是Name爲空則會有錯誤提示信息,而Major輸入字符串過多,也會有提示信息,而這些設置是來自模型的數據註解。

 

這個客戶端驗證是有jQueryvalidation插件提供的:

http://bassistance.de/jquery-plugins/jquery-plugin-validation/

 

若是你查看頁面源代碼,會發現Major輸入框的input標籤上有相應的自定義屬性data-val-length-max=200data-val-length,而這些屬性值正是來自於模型的數據註解。

 

控制器的服務器端驗證

在啓用JavaScript的狀況下,因爲全部的錯誤輸入在客戶端就會被攔截,因此根本到達不了服務器,不過這並不表示惡意用戶沒法提交錯誤的輸入,有不少種方法能夠作到:

 

禁用JavaScript

不一樣瀏覽器禁用JavaScript的方法不一樣,在Chrome中,F12打開開發工具,而後找到設置對話框:

 

 

此時提交頁面,你會看到和前面徹底相同的頁面,因爲本地運行速度很快,你甚至可能沒意識已經發起了一次HTTP POST請求,而顯示錯誤提示的頁面來自服務器,而不是客戶端:

 

響應正文包含以下內容,其中錯誤信息是服務器端生成的:

<div class="form-group">

       <label class="control-label col-md-2" for="Name">Name</label>

       <div class="col-md-10">

              <input class="input-validation-error form-control text-box single-line" data-val="true" data-val-length="字段 Name 必須是最大長度爲 200 的字符串。" data-val-length-max="200" data-val-required="Name 字段是必需的。" id="Name" name="Name" type="text" value="" />

              <span class="field-validation-error text-danger" data-valmsg-for="Name" data-valmsg-replace="true">Name 字段是必需的。</span>

       </div>

</div>

 

 

此時再回過頭來看下Students控制器中Create操做方法的定義:

[HttpPost]

[ValidateAntiForgeryToken]

public ActionResult Create([Bind(Include = "ID,Name,Gender,Major,EntranceDate")] Student student)

{

       if (ModelState.IsValid)

       {

              db.Students.Add(student);

              db.SaveChanges();

              return RedirectToAction("Index");

       }

 

       return View(student);

}

 

 

若是驗證失敗,則不更新數據庫,並返回帶Student模型的視圖。

 

模擬POST請求

有不少工具能夠模擬POST,這裏咱們講解若是使用Fiddler來模擬項服務器提交POST請求。

打開Fiddler,就開始自動監測全部的HTTP請求,這時咱們刷新Create頁面,並在JavaScript禁用的狀況下,提交表單,這時會有兩個請求:

 

首先選中左側的第二個請求,右側面板中選擇Inspectors->WebForms,下面會顯示三個窗格:

1.     QueryString:當前請求的URL查詢字符串。

2.     BodyPOST請求的表單參數。

3.     第三部分:響應正文,咱們能夠看到服務器端返回的錯誤信息。

 

如今切換到Composer選項卡,咱們能夠在這裏面模擬POST請求:

 

上面有一段提示信息:使用這個頁面建立一個請求。你能夠經過拖拽的方式從左側會話列表中拷貝一個以前的請求。

 

這就方便多了,咱們從左側選中第二個請求並拖拽到本頁面:

 

這時頁面背景變成明顯的綠色以做提示,拖拽結束:

 

這時,Fiddler自動幫咱們設置了模擬POST請求的參數,拷貝自以前的某個請求,這時的[Request Body]是通過URL編碼的,咱們能夠方便的進行解碼:

 

咱們把這段代碼修改爲:

__RequestVerificationToken=wwoxICDootbixw8YMiFIOU1WW95QSCicREsWLeewlSAE28sdyEA0ZChlY0nfuOlxu2WDIjcrx086GYkaBOAtewyARWbeRZp0kD6tRt-hyAs1&Name=張三石&Gender=1&Major=&EntranceDate=2000-09-01

 

把這段字符串拷貝到Fiddler中的[Request Body],並點擊[Execute]按鈕,這時會發起一個新的模擬請求:

 

注意這個請求並非從頁面發出的,而是經過工具模擬的HTTP POST請求,而且咱們還修改了其中的表單參數(Name=張三石,Major=空字符串),這樣固然也就會躲開瀏覽器端的JavaScript驗證規則,可是仍是沒法穿透服務器端的驗證。

 

這也正是MVC中數據註解帶來的便利,一個地方定義,三個地方使用(數據庫表結構、客戶端驗證,服務器端驗證)。

 

小結

本章咱們首先查看了EF自動生成的數據庫結構,而後爲數據模型添加數據註解,繼而介紹了數據遷移的工做過程。數據註解不只對數據庫表結構產生影響,並且會應用到前臺的客戶端驗證和服務器端驗證,接下來咱們詳細講解了兩則躲避客戶端驗證的手段,分別爲禁用JavaScript和模擬POST請求。從而更加深入的認識到數據註解給咱們提供的便利:一個地方定義,三個地方使用(數據庫表結構、客戶端驗證,服務器端驗證)

在建立新用戶頁面,咱們能夠看到兩個安全相關的代碼(ValidateAntiForgeryTokenBind),它們分別用於阻止CSRF跨站請求僞造和Over-Posting過多提交攻擊,下一篇文章咱們會詳細介紹。

下載示例源代碼

相關文章
相關標籤/搜索