日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

ASP.NET MVC 4 (十) 模型验证

發(fā)布時(shí)間:2024/10/12 asp.net 114 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET MVC 4 (十) 模型验证 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

模型驗(yàn)證是在模型綁定時(shí)檢查從HTTP請(qǐng)求接收的數(shù)據(jù)是否合規(guī)以保證數(shù)據(jù)的有效性,在收到無(wú)效數(shù)據(jù)時(shí)給出提示幫助用戶糾正錯(cuò)誤的數(shù)據(jù)。

顯式模型驗(yàn)證

驗(yàn)證數(shù)據(jù)最直接的方式就是在action方法中對(duì)接收的數(shù)據(jù)驗(yàn)證,以下面的Model為例:

public class Appointment {public string ClientName { get; set; }public DateTime Date { get; set; }public bool TermsAccepted { get; set; }}

我們要求ClientName不能為空;約會(huì)日期Date不能早于當(dāng)前日期,日期的格式可以在web.config中使用<globalization culture="en-US" uiCulture="enUS"/>來(lái)指定,否則使用服務(wù)器默認(rèn)的時(shí)區(qū)格式;TermsAccepted必須為true。我們?cè)贛akeBooking.cshtml視圖中收集數(shù)據(jù):

@model ModelValidation.Models.Appointment @{ ViewBag.Title = "Make A Booking"; } <h4>Book an Appointment</h4> @using (Html.BeginForm()) { <p>Your name: @Html.EditorFor(m => m.ClientName)</p> <p>Appointment Date: @Html.EditorFor(m => m.Date)</p> <p>@Html.EditorFor(m => m.TermsAccepted) I accept the terms & conditions</p> <input type="submit" value="Make Booking" /> }

直接在action方法中驗(yàn)證請(qǐng)求的數(shù)據(jù):

... [HttpPost] public ViewResult MakeBooking(Appointment appt) { if (string.IsNullOrEmpty(appt.ClientName)) { ModelState.AddModelError("ClientName", "Please enter your name"); } if (ModelState.IsValidField("Date") && DateTime.Now > appt.Date) { ModelState.AddModelError("Date", "Please enter a date in the future"); } if (!appt.TermsAccepted) { ModelState.AddModelError("TermsAccepted", "You must accept the terms"); } if (ModelState.IsValid) { // statements to store new Appointment in a // repository would go here in a real project return View("Completed", appt); } else { return View(); } } ...

ModelState.IsValidField()檢查模型綁定器能否成功綁定“Date”屬性,如果數(shù)據(jù)不合法使用ModelState.AddModelError()添加錯(cuò)誤消息。如果沒(méi)有任何錯(cuò)誤,ModelState.IsValid=true,我們可以繼續(xù)正常操作,否則返回?cái)?shù)據(jù)輸入界面。HTML.EditFor()幫助函數(shù)會(huì)檢查ModelState是否包含當(dāng)前屬性的錯(cuò)誤,如果有錯(cuò)誤會(huì)為生成的元素添加CSS類input-validation-error,默認(rèn)的input-validation-error類定義在~/Content/Site.css中:

... .input-validation-error { border: 1px solid #f00; background-color: #fee; } ...

其效果就是使得輸入控件邊框變紅、背景變粉紅以提示用戶有錯(cuò)誤發(fā)生。如果自己編寫的HTML幫助函數(shù)要支持驗(yàn)證錯(cuò)誤提示,可以參考System.Mvc.Web.Html.InputExtensions的源代碼是如何實(shí)現(xiàn)的。

一些瀏覽器比如Chrome和Firefox會(huì)忽略應(yīng)用在復(fù)選框Checkbox上的CSS屬性,我們可以通過(guò)前面講到的自定義模板來(lái)解決:

@model bool?@if (ViewData.ModelMetadata.IsNullableValueType) {@Html.DropDownListFor(m => m, new SelectList(new [] {"Not Set", "True", "False"}, Model)) } else {ModelState state = ViewData.ModelState[ViewData.ModelMetadata.PropertyName];bool value = Model ?? false;if (state != null && state.Errors.Count > 0) {<div class="input-validation-error" style="float:left">@Html.CheckBox("", value)</div>} else {@Html.CheckBox("", value) } }

這里定義了一個(gè)bool類型專用的自定義模板,使用div標(biāo)簽包裝checkbox,從modelstate檢查當(dāng)前屬性是否有錯(cuò)誤,有錯(cuò)誤時(shí)添加錯(cuò)誤提示的CSS類到div標(biāo)簽上。

顯示驗(yàn)證消息

除了通過(guò)CSS風(fēng)格提示錯(cuò)誤,我們可以將添加到modelstate的錯(cuò)誤消息在視圖中顯示給用戶:

@model ModelValidation.Models.Appointment @{ ViewBag.Title = "Make A Booking"; } <h4>Book an Appointment</h4> @using (Html.BeginForm()) { @Html.ValidationSummary() <p>Your name: @Html.EditorFor(m => m.ClientName)</p> <p>Appointment Date: @Html.EditorFor(m => m.Date)</p> <p>@Html.EditorFor(m => m.TermsAccepted) I accept the terms & conditions</p> <input type="submit" value="Make Booking" /> }

?Html.ValidationSummary()幫助函數(shù)將ModelState中的錯(cuò)誤消息以列表的方式羅列出來(lái)顯示給用戶。ValidationSummary有幾種重載形式:

重載形式說(shuō)明
Html.ValidationSummary()?匯總顯示所有的驗(yàn)證錯(cuò)誤
Html.ValidationSummary(bool)如果bool參數(shù)=true,只顯示Model層次的錯(cuò)誤,否則所有的驗(yàn)證錯(cuò)誤都顯示
Html.ValidationSummary(string)?在所有錯(cuò)誤消息之前再顯示string給出的字符串
Html.ValidationSummary(bool, string)?同Html.ValidationSummary(bool),只是在錯(cuò)誤消息前多顯示string給出的字符串

所謂Model層次的錯(cuò)誤,其實(shí)就是使用ModelState.AddModelError()添加錯(cuò)誤消息時(shí)第一個(gè)代表錯(cuò)誤屬性的參數(shù)留空,比如:

... if (ModelState.IsValidField("ClientName") && ModelState.IsValidField("Date") && appt.ClientName == "Joe" && appt.Date.DayOfWeek == DayOfWeek.Monday) { ModelState.AddModelError("", "Joe cannot book appointments on Mondays"); } ...

除了Html.ValidationSummary(),我們可以將錯(cuò)誤消息緊鄰輸入控件挨個(gè)顯示:

@model ModelValidation.Models.Appointment @{ViewBag.Title = "Make A Booking"; } <h4>Book an Appointment</h4> @using (Html.BeginForm()) {@Html.ValidationSummary(true)<p>@Html.ValidationMessageFor(m => m.ClientName)</p><p>Your name: @Html.EditorFor(m => m.ClientName)</p><p>@Html.ValidationMessageFor(m => m.Date)</p><p>Appointment Date: @Html.EditorFor(m => m.Date)</p><p>@Html.ValidationMessageFor(m => m.TermsAccepted)</p><p>@Html.EditorFor(m => m.TermsAccepted) I accept the terms & conditions</p><input type="submit" value="Make Booking" /> }

Html.ValidationMessageFor()在屬性有錯(cuò)誤時(shí)顯示對(duì)應(yīng)的錯(cuò)誤消息,為避免在匯總消息中重復(fù)顯示,這里使用true參數(shù)調(diào)用Html.ValidationSummary(true)。

模型綁定時(shí)驗(yàn)證

默認(rèn)模型綁定器DefaultModelBinder內(nèi)建在綁定時(shí)驗(yàn)證數(shù)據(jù),比如我們輸入非日期格式給Date屬性,綁定器會(huì)給出“The value 'xxx' is not valid for Date.”的錯(cuò)誤消息。我們可以重載DefaultModelBinder的一些方法來(lái)添加有用的信息:

方法說(shuō)明默認(rèn)實(shí)現(xiàn)的功能
OmModelUpdated在綁定器試圖給模型對(duì)象所有屬性賦值時(shí)調(diào)用根據(jù)模型metadata給出的驗(yàn)證規(guī)則驗(yàn)證數(shù)據(jù)添加錯(cuò)誤消息到ModelState
SetProperty在綁定器視圖給模型對(duì)象的某個(gè)屬性賦值時(shí)調(diào)用如果模型屬性不能是Null但是沒(méi)有數(shù)據(jù)來(lái)綁定時(shí)添加“The <name> field?is required”消息到ModelState,如果有數(shù)據(jù)但是處理錯(cuò)誤比如類型轉(zhuǎn)換失敗添加“The value <value> is not valid?for <name>”消息到ModelState

使用元數(shù)據(jù)指定驗(yàn)證規(guī)則

更多的時(shí)候我們不需要重載默認(rèn)模型綁定器,因?yàn)槲覀兛梢愿奖愕氖褂胢etadata在數(shù)據(jù)模型上添加驗(yàn)證規(guī)則:

public class Appointment { [Required] public string ClientName { get; set; } [DataType(DataType.Date)] [Required(ErrorMessage="Please enter a date")] public DateTime Date { get; set; } [Range(typeof(bool), "true", "true", ErrorMessage = "You must accept the terms")] public bool TermsAccepted { get; set; } }

這里使用了Required和Range兩個(gè)特性,前者表示數(shù)據(jù)是必須的,后者指定了一個(gè)可用值范圍;ErrorMessage則是錯(cuò)誤時(shí)的提示消息,如果不指定則使用上表中的默認(rèn)消息。可用的驗(yàn)證特性包括:

特性示例說(shuō)明
Compare[Compare("MyOtherProperty")]兩個(gè)屬性必須相同值,比如我們要求用戶重復(fù)輸入兩次郵件地址時(shí)有用
Range[Range(10, 20)]?屬性值必須在指定的數(shù)值范圍內(nèi),可以使用數(shù)值類型的最大最小值比如int.MinValue、int.MaxValue
RegularExpression[RegularExpression("pattern")]?字符串值必須匹配正則表達(dá)式,默認(rèn)大小寫敏感,可以使用(?i)修飾符關(guān)閉大小寫敏感,比如[RegularExpression("(?i)mypattern")]
Required[Required]屬性值必須非空或者不能只是空格,如果允許全空格可以[Required(AllowEmptyStrings = true)]
StringLength[StringLength(10)]?字符串長(zhǎng)度不能超過(guò)給定的最大長(zhǎng)度,也可以指定最小長(zhǎng)度:[StringLength(10, MinimumLength=2)]

上面的例子中沒(méi)有使用Required特性驗(yàn)證bool類型的TermsAccepted,這是因?yàn)镋ditFor()在渲染Checkbox會(huì)多給出一個(gè)hidden的輸入元素,即使我們沒(méi)有選中checkbox返回的結(jié)果中仍然是有值的。使用Range看上去比較別扭,好在我們可以創(chuàng)建自定義的驗(yàn)證特性類來(lái)改進(jìn):

public class MustBeTrueAttribute : ValidationAttribute {public override bool IsValid(object value) {return value is bool && (bool)value;}}

這里驗(yàn)證輸入數(shù)據(jù)是否是bool類型且為true,使用這個(gè)自定義驗(yàn)證特性很簡(jiǎn)單:

.. [MustBeTrue(ErrorMessage="You must accept the terms")] public bool TermsAccepted { get; set; } ...

除了從ValidationAttribute擴(kuò)展自定義特性,我們可以直接從內(nèi)建的驗(yàn)證特性擴(kuò)展:

public class FutureDateAttribute : RequiredAttribute {public override bool IsValid(object value) {return base.IsValid(value) && ((DateTime)value) > DateTime.Now;}}

這里從Require驗(yàn)證特性擴(kuò)展,在調(diào)用基類的驗(yàn)證后再做附加的檢查。

以上的驗(yàn)證特性都是針對(duì)模型單個(gè)屬性的,我們還可以為整個(gè)模型創(chuàng)建自定義驗(yàn)證特性:

public class NoJoeOnMondaysAttribute : ValidationAttribute {public NoJoeOnMondaysAttribute() {ErrorMessage = "Joe cannot book appointments on Mondays";}public override bool IsValid(object value) {Appointment app = value as Appointment;if (app == null || string.IsNullOrEmpty(app.ClientName) || app.Date == null) {// we don't have a model of the right type to validate, or we don't have// the values for the ClientName and Date properties we requirereturn true;} else {return !(app.ClientName == "Joe" && app.Date.DayOfWeek == DayOfWeek.Monday);} }}

這里檢查客戶名稱和約定日期,不允許客戶名稱Joe在星期一預(yù)約,我們可以將這個(gè)特性應(yīng)用在整個(gè)模型類上:

[NoJoeOnMondays] public class Appointment { [Required] public string ClientName { get; set; } [DataType(DataType.Date)] [FutureDate(ErrorMessage="Please enter a date in the future")] public DateTime Date { get; set; } [MustBeTrue(ErrorMessage="You must accept the terms")] public bool TermsAccepted { get; set; } }

有了這些驗(yàn)證規(guī)則特性,控制器類的action方法可以極大的簡(jiǎn)化為:

... [HttpPost]public ViewResult MakeBooking(Appointment appt) {if (ModelState.IsValid) {// statements to store new Appointment in a// repository would go here in a real projectreturn View("Completed", appt);} else {return View();}} ...

自驗(yàn)證模型

模型驗(yàn)證的另外一種是為模型類實(shí)現(xiàn)IValidatableObject接口創(chuàng)建可自驗(yàn)證的模型類:

using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using ModelValidation.Infrastructure; namespace ModelValidation.Models {public class Appointment : IValidatableObject{public string ClientName { get; set; }[DataType(DataType.Date)]public DateTime Date { get; set; }public bool TermsAccepted { get; set; }public IEnumerable<ValidationResult> Validate(ValidationContext validationContext){List<ValidationResult> errors = new List<ValidationResult>();if (string.IsNullOrEmpty(ClientName)){errors.Add(new ValidationResult("Please enter your name"));}if (DateTime.Now > Date){errors.Add(new ValidationResult("Please enter a date in the future"));}if (errors.Count == 0 && ClientName == "Joe"&& Date.DayOfWeek == DayOfWeek.Monday){errors.Add(new ValidationResult("Joe cannot book appointments on Mondays"));}if (!TermsAccepted){errors.Add(new ValidationResult("You must accept the terms"));}return errors;}} }

模型綁定器在試圖給模型對(duì)象賦值時(shí)調(diào)用Validate(),返回結(jié)果是一個(gè)錯(cuò)誤列表,使用這種方式我們可以在一個(gè)地方做完所有的數(shù)據(jù)驗(yàn)證。

客戶端驗(yàn)證

以上講的都是數(shù)據(jù)提交到服務(wù)器上后的驗(yàn)證,客戶端我們可以通過(guò)腳本在數(shù)據(jù)提交到服務(wù)器前驗(yàn)證,MVC支持“unobtrusive client-side validation”,unobtrusive意指在輸出HTML標(biāo)簽時(shí)添加特定HTML標(biāo)簽,過(guò)MVC的JAVA腳本驗(yàn)證庫(kù)利用這些專用特性進(jìn)行數(shù)據(jù)驗(yàn)證。要使用客戶端驗(yàn)證首先需要在web.config中啟用:

... <appSettings> <add key="ClientValidationEnabled" value="true"/> <add key="UnobtrusiveJavaScriptEnabled" value="true"/> </appSettings> ...

上面的兩個(gè)設(shè)置必須都為true,我們可以在Razor代碼塊中使用HtmlHelper.ClientValidationEnabled和HtmlHelper.UnobtrusiveJavaScriptEnabled為單個(gè)視圖配置是否使用客戶端驗(yàn)證。我們還必須保證以下腳本文件被添加到視圖或者布局文件中:

  • /Scripts/ jquery-1.7.1.min.js
  • /Scripts/ jquery.validate.min.js
  • /Scripts/ jquery.validate.unobtrusive.min.js

可以看到客戶端驗(yàn)證仍然是依賴于Jquery的。在啟用客戶端驗(yàn)證后,我們添加到模型類上的內(nèi)建驗(yàn)證特性比如Requried、StringLength就可以直接工作了,數(shù)據(jù)驗(yàn)證錯(cuò)誤時(shí)java腳本會(huì)給出錯(cuò)誤提示。具體來(lái)講EditFor()這些模板幫助函數(shù)在啟用客戶端驗(yàn)證后會(huì)輸出一些額外的特性,比如上面ClientName屬性:

... <input class="text-box single-line" data-val="true" data-val-length="The field ClientName must be a string with a minimum length of 3 and a maximum length of 10." data-val-length-max="10" data-val-length-min="3" data-val-required="The ClientName field is required." id="ClientName" name="ClientName" type="text" value="" /> ...

JQuery驗(yàn)證函數(shù)查找data-val=true的元素進(jìn)行驗(yàn)證,data-val-<xxx>則是具體的驗(yàn)證規(guī)則,比如這里的data-val-length和data-val-required。通過(guò)元數(shù)據(jù)指定的驗(yàn)證規(guī)則既可以在客戶端使用,也可以在服務(wù)器端使用,為我們帶來(lái)了極大的方便,而且即使在客戶端禁用了JAVA腳本,服務(wù)器端的數(shù)據(jù)驗(yàn)證仍然有效。

遠(yuǎn)程驗(yàn)證

遠(yuǎn)程驗(yàn)證是客戶端驗(yàn)證和服務(wù)端驗(yàn)證的折中方式,客戶端在背后通過(guò)Ajax請(qǐng)求向服務(wù)端驗(yàn)證數(shù)據(jù),典型的應(yīng)用場(chǎng)景可以是用戶名的驗(yàn)證,在用戶名驗(yàn)證成功后才允許用戶繼續(xù)后續(xù)的輸入。使用遠(yuǎn)程驗(yàn)證是從控制器定義一個(gè)用于驗(yàn)證的action方法開(kāi)始:

... public JsonResult ValidateDate(string Date) {DateTime parsedDate;if (!DateTime.TryParse(Date, out parsedDate)) {return Json("Please enter a valid date (mm/dd/yyyy)",JsonRequestBehavior.AllowGet);} else if (DateTime.Now > parsedDate) {return Json("Please enter a date in the future", JsonRequestBehavior.AllowGet);} else {return Json(true, JsonRequestBehavior.AllowGet);}} ...

驗(yàn)證action方法必須有一個(gè)和要驗(yàn)證字段同名的參數(shù),這里定義Date為字符串類型是有考慮的。模型綁定如果不能從請(qǐng)求數(shù)據(jù)中轉(zhuǎn)換成日期類型會(huì)發(fā)生異常,遠(yuǎn)程驗(yàn)證無(wú)法在客戶端顯示異常信息會(huì)被靜悄悄的丟棄,所以一般我們使用字符串類型,在驗(yàn)證方法內(nèi)部顯式的轉(zhuǎn)換數(shù)據(jù)類型。驗(yàn)證方法返回一個(gè)返回一個(gè)JsonResult對(duì)象,驗(yàn)證成功我們封裝true,不成功封裝錯(cuò)誤信息,無(wú)論哪種結(jié)果我們使用JsonRequestBehavior.AllowGet標(biāo)識(shí)驗(yàn)證結(jié)果可以通過(guò)GET請(qǐng)求。

有了遠(yuǎn)程驗(yàn)證action,我們需要添加remote驗(yàn)證特性到相應(yīng)的模型類屬性上:

public class Appointment {[Required][StringLength(10, MinimumLength = 3)]public string ClientName { get; set; }[DataType(DataType.Date)][Remote("ValidateDate", "Home")]public DateTime Date { get; set; }public bool TermsAccepted { get; set; }}

在Remote驗(yàn)證特性中指定用于驗(yàn)證的控制器名稱和action,MVC的javascript驗(yàn)證庫(kù)按此生成的URL請(qǐng)求并驗(yàn)證。遠(yuǎn)程驗(yàn)證會(huì)在用戶第一次提交表單時(shí)生效,以及此后的每一次編輯數(shù)據(jù)的動(dòng)作,比如每一次的按鍵都會(huì)執(zhí)行一次遠(yuǎn)程驗(yàn)證,這是我們?cè)趲捰邢迺r(shí)需要考慮的。

以上為對(duì)《Apress Pro ASP.NET MVC 4》第四版相關(guān)內(nèi)容的總結(jié),不詳之處參見(jiàn)原版 http://www.apress.com/9781430242369。

轉(zhuǎn)載于:https://www.cnblogs.com/GoogleGetZ/p/5835805.html

與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的ASP.NET MVC 4 (十) 模型验证的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。