溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證

發(fā)布時(shí)間:2021-08-09 10:28:47 來源:億速云 閱讀:181 作者:小新 欄目:開發(fā)技術(shù)

這篇文章給大家分享的是有關(guān)ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

首先我們創(chuàng)建一個(gè)ASP.NET MVC項(xiàng)目,本人環(huán)境是VS2017,

ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證

創(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

ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證

將默認(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ò)誤消息顯示出來了。

接下來我們將程序跑起來。

ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證

ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證

正如大家所看到的,當(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)證的。

ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證

感謝各位的閱讀!關(guān)于“ASP.NET之在MVC中如何使用服務(wù)端驗(yàn)證”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(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)容。

AI