您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關(guān)ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。
首先我們創(chuàng)建一個(gè)ASP.NET MVC項(xiàng)目,本人環(huán)境是VS2017,
創(chuàng)建成功后通過在Nuget中使用 Install-Package FluentValidation -Version 7.6.104 安裝FluentValidation
在Model文件夾中添加兩個(gè)實(shí)體Address 和 Person
public class Address { public string Home { get; set; } public string Phone { get; set; } }
public class Person { /// <summary> /// 姓名 /// </summary> public string Name { get; set; } /// <summary> /// 年齡 /// </summary> public int Age { get; set; } /// <summary> /// 性別 /// </summary> public bool Sex { get; set; } /// <summary> /// 地址 /// </summary> public Address Address { get; set; } }
緊接著創(chuàng)建實(shí)體的驗(yàn)證器
public class AddressValidator : AbstractValidator<Address> { public AddressValidator() { this.RuleFor(m => m.Home) .NotEmpty() .WithMessage("家庭住址不能為空"); this.RuleFor(m => m.Phone) .NotEmpty() .WithMessage("手機(jī)號碼不能為空"); } }
public class PersonValidator : AbstractValidator<Person> { public PersonValidator() { this.RuleFor(p => p.Name) .NotEmpty() .WithMessage("姓名不能為空"); this.RuleFor(p => p.Age) .NotEmpty() .WithMessage("年齡不能為空"); this.RuleFor(p => p.Address) .SetValidator(new AddressValidator()); } }
為了更好的管理驗(yàn)證器,我建議將使用一個(gè)Manager者來管理所有驗(yàn)證器的實(shí)例。如ValidatorHub
public class ValidatorHub { public AddressValidator AddressValidator { get; set; } = new AddressValidator(); public PersonValidator PersonValidator { get; set; } = new PersonValidator(); }
現(xiàn)在我們需要?jiǎng)?chuàng)建一個(gè)頁面,在默認(rèn)的HomeController 控制器下添加2個(gè)Action:ValidatorTest,他們一個(gè)用于展示頁面,另一個(gè)則用于提交。
[HttpGet] public ActionResult ValidatorTest() { return View(); } [HttpPost] public ActionResult ValidatorTest(Person model) { return View(); }
為 ValidatorTest 添加視圖,選擇Create模板,實(shí)體為Person
將默認(rèn)的@Html全部刪掉,因?yàn)樵谖覀儽敬谓榻B中不需要,我們的目標(biāo)是搭建一個(gè)前后端分離的項(xiàng)目,而不要過多的依賴于MVC。
最終我們將表單改寫成了
@using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h5>Person</h5> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div class="form-group"> <label for="Name" class="control-label col-md-2">姓名</label> <div class="col-md-10"> <input type="text" name="Name" class="form-control" /> </div> </div> <div class="form-group"> <label for="Age" class="control-label col-md-2">年齡</label> <div class="col-md-10"> <input type="text" name="Age" class="form-control" /> </div> </div> <div class="form-group"> <label for="Home" class="control-label col-md-2">住址</label> <div class="col-md-10"> <input type="text" name="Address.Home" class="form-control" /> </div> </div> <div class="form-group"> <label for="Phone" class="control-label col-md-2">電話</label> <div class="col-md-10"> <input type="text" name="Address.Phone" class="form-control" /> </div> </div> <div class="form-group"> <label for="Sex" class="control-label col-md-2">性別</label> <div class="col-md-10"> <div class="checkbox"> <input type="checkbox" name="Sex" /> </div> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Create" class="btn btn-default" /> </div> </div> </div> }
注意,由于我們的實(shí)體Person中存在復(fù)雜類型Address,我們都知道,表單提交默認(rèn)是Key:Value形式,而在傳統(tǒng)表單的key:value中,我們無法實(shí)現(xiàn)讓key為Address的情況下Value為一個(gè)復(fù)雜對象,因?yàn)閕nput一次只能承載一個(gè)值,且必須是字符串。實(shí)際上MVC中存在模型綁定,此處不作過多介紹(因?yàn)槲乙餐浟?_-||)。
簡單的說就是他能根據(jù)你所需要類型幫我們自動(dòng)盡可能的轉(zhuǎn)換,我們目前只要知道如何正確使用,在Address中存在Home屬性和Phone屬性,我們可以將表單的name設(shè)置為Address.Home,MVC的模型綁定會(huì)將Address.Home解析到對象Address上的Home屬性去。
簡單的校驗(yàn)方式我也不過多介紹了。再上一章我們已經(jīng)了解到通過創(chuàng)建一個(gè)實(shí)體的驗(yàn)證器來對實(shí)體進(jìn)行驗(yàn)證,然后通過IsValid屬性判斷是否驗(yàn)證成功。對,沒錯(cuò),對于大家來說這太簡單了。但我們每次校驗(yàn)都創(chuàng)建一個(gè)驗(yàn)證器是否顯得有點(diǎn)麻煩呢?不要忘了我們剛剛創(chuàng)建了一個(gè)ValidatorHub,我們知道控制器默認(rèn)繼承自Controller,如果我們想為控制器擴(kuò)展一些能力呢?現(xiàn)在我要?jiǎng)?chuàng)建一個(gè)ControllerEx了,并繼承自Controller。
public class ControllerEx : Controller { protected Dictionary<string, string> DicError { get; set; } = new Dictionary<string, string>(); protected ValidatorHub ValidatorHub { get; set; } = new ValidatorHub(); protected override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); ViewData["Error"] = DicError; } protected void ValidatorErrorHandler(ValidationResult result) { foreach (var failure in result.Errors) { if (!this.DicError.ContainsKey(failure.PropertyName)) { this.DicError.Add(failure.PropertyName, failure.ErrorMessage); } } } }
在ControllerEx里我創(chuàng)建了一個(gè)ValidatorHub屬性,正如其名,他內(nèi)部存放著各種驗(yàn)證器實(shí)體呢。有了它,我們可以在需要驗(yàn)證的Action中通過this.ValidatorHub.具體驗(yàn)證器就能完成具體驗(yàn)證工作了,而不需要再去每次new 一個(gè)驗(yàn)證器。
同樣我定義了一個(gè)DicError的鍵值對集合,他的鍵和值類型都是string。key是驗(yàn)證失敗的屬性名,而value則是驗(yàn)證失敗后的錯(cuò)誤消息,它是用來存在驗(yàn)證的結(jié)果的。
在這里我還定義了一個(gè)ValidatorErrorHandler的方法,他有一個(gè)參數(shù)是驗(yàn)證結(jié)果,通過名稱我們大致已經(jīng)猜到功能了,驗(yàn)證錯(cuò)誤的處理,對驗(yàn)證結(jié)果的錯(cuò)誤信息進(jìn)行遍歷,并將錯(cuò)誤信息添加至DicError集合。
最終我需要將這個(gè)DicError傳遞給View,簡單的辦法是ViewData["Error"] 但我不想在每個(gè)頁面都去這么干,因?yàn)檫@使我要重復(fù)多次寫這行代碼,我會(huì)厭倦它的。很棒的是MVC框架為我們提供了Filter(有的地方也稱函數(shù)鉤子,切面編程,過濾器),能夠方便我們在生命周期的不同階段進(jìn)行控制,很顯然,我的需求是在每次執(zhí)行完Action后要在末尾添加一句ViewData["Error"]=DicError。于是我重寫了OnActionExecuted方法,僅添加了 ViewData["Error"] = DicError;
現(xiàn)在我只需要將HomeController繼承自ControllerEx即可享受以上所有功能了。
現(xiàn)在基本工作基本都完成了,但我們還忽略了一個(gè)問題,我錯(cuò)誤是存在了ViewData["Error"]里傳遞給View,只不過難道我們在驗(yàn)證錯(cuò)誤的時(shí)候在頁面顯示一個(gè)錯(cuò)誤列表?像li一樣?這顯然不是我們想要的。我們還需要一個(gè)幫助我們合理的顯示錯(cuò)誤信息的函數(shù)。在Razor里我們可以對HtmlHelper進(jìn)行擴(kuò)展。于是我為HtmlHelper擴(kuò)展了一個(gè)方法ValidatorMessageFor
public static class ValidatorHelper { public static MvcHtmlString ValidatorMessageFor(this HtmlHelper htmlHelper, string property, object error) { var dicError = error as Dictionary<string, string>; if (dicError == null) //沒有錯(cuò)誤 { // 不會(huì)等于空 } else { if (dicError.ContainsKey(property)) { return new MvcHtmlString(string.Format("<p>{0}</p>", dicError[property])); } } return new MvcHtmlString(""); } }
在ValidatorMessaegFor里需要2個(gè)參數(shù)property 和 error
前者是需要顯示的錯(cuò)誤屬性名,后者則是錯(cuò)誤對象即ViewData["Error"],功能很簡單,在發(fā)現(xiàn)錯(cuò)誤對象里存在key為錯(cuò)誤屬性名的時(shí)候?qū)alue用一個(gè)p標(biāo)簽包裹起來返回,value即為錯(cuò)誤屬性所對應(yīng)的錯(cuò)誤提示消息。
現(xiàn)在我們還需要在View每一個(gè)input下添加一句如: @Html.ValidatorMessageFor("Name", ViewData["Error"])即可。
@using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h5>Person</h5> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div class="form-group"> <label for="Name" class="control-label col-md-2">姓名</label> <div class="col-md-10"> <input type="text" name="Name" class="form-control" /> @Html.ValidatorMessageFor("Name", ViewData["Error"]) </div> </div> <div class="form-group"> <label for="Age" class="control-label col-md-2">年齡</label> <div class="col-md-10"> <input type="text" name="Age" class="form-control" /> @Html.ValidatorMessageFor("Name", ViewData["Error"]) </div> </div> <div class="form-group"> <label for="Home" class="control-label col-md-2">住址</label> <div class="col-md-10"> <input type="text" name="Address.Home" class="form-control" /> @Html.ValidatorMessageFor("Address.Home", ViewData["Error"]) </div> </div> <div class="form-group"> <label for="Phone" class="control-label col-md-2">電話</label> <div class="col-md-10"> <input type="text" name="Address.Phone" class="form-control" /> @Html.ValidatorMessageFor("Address.Phone", ViewData["Error"]) </div> </div> <div class="form-group"> <label for="Sex" class="control-label col-md-2">性別</label> <div class="col-md-10"> <div class="checkbox"> <input type="checkbox" name="Sex" /> </div> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Create" class="btn btn-default" /> </div> </div> </div> }
到此我們的所有基本工作都已完成
[HttpPost] public ActionResult ValidatorTest(Person model) { var result = this.ValidatorHub.PersonValidator.Validate(model); if (result.IsValid) { return Redirect("https://www.baidu.com"); } else { this.ValidatorErrorHandler(result); } return View(); }
通過我們在ControllerEx種的ValidatorHub來對實(shí)體Person進(jìn)行校驗(yàn),如果校驗(yàn)成功了....這里沒啥可干的就當(dāng)跳轉(zhuǎn)一下表示咯,否則的話調(diào)用Ex中的ValidatorErrorHandler 將錯(cuò)誤消息綁定到ViewData["Error"]中去,這樣就能在前端View渲染的時(shí)候?qū)㈠e(cuò)誤消息顯示出來了。
接下來我們將程序跑起來。
正如大家所看到的,當(dāng)我點(diǎn)擊提交的時(shí)候 雖然只有電話沒輸入但其他三個(gè)表單被清空了,也許我們會(huì)覺得不爽,當(dāng)然如果你需要那相信你在看完上述的錯(cuò)誤信息綁定后一定也能解決這個(gè)問題的,但事實(shí)上,我們并不需要它,\(^o^)/~
為什么呢?因?yàn)槲覀冞€要前端驗(yàn)證啊,當(dāng)前端驗(yàn)證沒通過的時(shí)候根本無法發(fā)送到后端來,所以不用擔(dān)心用戶在一部分驗(yàn)證失敗時(shí)已填寫的表單數(shù)據(jù)被清空掉。
這里提到在表單提交時(shí)需要前端校驗(yàn),既然有前端校驗(yàn)了為何還要我們做后臺校驗(yàn)?zāi)兀坎皇敲摿搜澴臃牌▎??事?shí)上,前端校驗(yàn)的作用在于優(yōu)化用戶體驗(yàn),減輕服務(wù)器壓力,也可以防住君子,但絕不能防止小人,由于Web客戶端的不確定性,任何東西都可以模擬的。如果不做服務(wù)端驗(yàn)證,假如你的系統(tǒng)涉及金錢,也許那天你醒來就發(fā)現(xiàn)自己破產(chǎn)了。
來一個(gè)通過驗(yàn)證的。
感謝各位的閱讀!關(guān)于“ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。