溫馨提示×

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

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

MVC下ASP.NET的表單驗(yàn)證的實(shí)現(xiàn)方法

發(fā)布時(shí)間:2021-07-12 16:26:29 來(lái)源:億速云 閱讀:174 作者:chen 欄目:編程語(yǔ)言

這篇文章主要介紹“MVC下ASP.NET的表單驗(yàn)證的實(shí)現(xiàn)方法”,在日常操作中,相信很多人在MVC下ASP.NET的表單驗(yàn)證的實(shí)現(xiàn)方法問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”MVC下ASP.NET的表單驗(yàn)證的實(shí)現(xiàn)方法”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

在Web開發(fā)中,表單提交算是一種很常見的從客戶端獲取數(shù)據(jù)的方式了。然而,用戶的行為永遠(yuǎn)都是無(wú)法預(yù)料的。為此,我們?cè)诔绦蛑胁坏靡驯仨殞?duì)用戶輸入的數(shù)據(jù)進(jìn)行嚴(yán)格效驗(yàn)。在WebForm時(shí)代我們常用的手段是驗(yàn)證控件,但是到了Mvc時(shí)代,再使用控件變得困難了,因此我們必須找到新的方式來(lái)解決這個(gè)問(wèn)題。
在實(shí)際使用中,我們可以考慮多種形式來(lái)進(jìn)行這一驗(yàn)證(注:本文目前只研究服務(wù)器端驗(yàn)證的情況),最直接的方式莫過(guò)于對(duì)每個(gè)表單值手動(dòng)用C#代碼進(jìn)行驗(yàn)證了,比如:

if(!Int32.TryParse(Request.Form[“age”], out age)){
xxxx…
}
If(age < xxx || age > xxx){
xxxx…
}


然而正如上面看到的一樣,這種方式枯燥而繁瑣,需要用戶對(duì)每個(gè)字段都要手動(dòng)效驗(yàn),或許開發(fā)人員的一不小心就會(huì)造成系統(tǒng)的漏洞。因此,制造出一個(gè)能對(duì)這種行為進(jìn)行自動(dòng)進(jìn)行的輪子勢(shì)在必行,當(dāng)然,到本文寫作的時(shí)候?yàn)橹?,?guó)外已經(jīng)出現(xiàn)了一些Mvc下使用的驗(yàn)證框架,然而天下輪子不怕多,我在此厚顏再造出個(gè),只希望不被冠上山寨之名。

該框架的締造源自4MVC團(tuán)隊(duì)的Infancy項(xiàng)目,去年年底開始這個(gè)項(xiàng)目的時(shí)候,正是mvc框架加入ModelBinder的時(shí)候,當(dāng)時(shí)便想到了通過(guò)使用ModelBinder來(lái)實(shí)現(xiàn)一種服務(wù)器端自動(dòng)驗(yàn)證框架,經(jīng)過(guò)多次修改,該框架慢慢實(shí)現(xiàn)了我需要的功能,本系列文章將再次回顧該過(guò)程,將該框架的一步步的實(shí)現(xiàn)過(guò)程加以更細(xì)致的重現(xiàn)。

下面正式開始框架的開發(fā),首先我們明確下我們的基本需求:

1.該框架針對(duì)簡(jiǎn)單實(shí)體類(POCO)

2.該框架能自動(dòng)對(duì)實(shí)體類的屬性進(jìn)行效驗(yàn)

3.該實(shí)體能被ModelBinder使用

4.能方便或者自動(dòng)的執(zhí)行該效驗(yàn),并取得效驗(yàn)結(jié)果和信息

為了實(shí)現(xiàn)上面的目標(biāo),我們首先來(lái)確定一些需要使用的技術(shù)手段:

1.要能訪問(wèn)任意POCO的屬性,必然用到反射
2.要能對(duì)屬性進(jìn)行限制,可選擇使用XML或者Attribute,對(duì)程序員來(lái)說(shuō),Attribute遠(yuǎn)比XML來(lái)的方便和友好,因此選擇Attribute

3.實(shí)現(xiàn)實(shí)體驗(yàn)證方法,可能會(huì)使用Command模式,也可能不需要

下面開始我們的實(shí)踐了,首先我們考慮測(cè)試代碼,假設(shè)我擁有實(shí)體Student,Student擁有屬性Source,要求Source是int類型,且范圍為0-100,那么測(cè)試代碼的模式應(yīng)該如下:

Student student = new Student(){
Source = -1
};
bool validateResult = student.Validate();
Assert.IsFalse(validateResult);


也就是說(shuō),我們需要在一個(gè)驗(yàn)證方法中對(duì)該對(duì)象的所有屬性進(jìn)行驗(yàn)證,那么我們考慮對(duì)系統(tǒng)各部分的構(gòu)建,首先我們需要一個(gè)RangeAttribute,這個(gè)類能包含對(duì)屬性的驗(yàn)證信息,大致如下:

public class RangeAttribute : Attribute{
public int Mix{ get; set; } //范圍下限
public int Max{ get; set; } //范圍上限
public string Message{ get; set;} //出錯(cuò)信息
public RangeAttribute(int min, int max, string message){
Min = min;
Max = max;
Message = message;
}
}



這樣一來(lái)我們的Student就可以如此構(gòu)造

public class Student{
[Range(0, 100, “分?jǐn)?shù)的范圍必須在{0}和{1}之間.”)]
public int Source{ get; set; }
}



然而,這樣僅僅是個(gè)花架子,在默認(rèn)情況下這個(gè)Range沒(méi)有起到任何作用,除了程序員看到代碼之后知道了Source有這樣的限制要求,那么,我們需要如何將這個(gè)Attribute和驗(yàn)證結(jié)合起來(lái)呢?自然就是反射。

我們?cè)赟tudent中實(shí)現(xiàn)如下方法:

public bool Validate(){
bool result = true;
Type type = this.GetType();
PropertyInfo property = type.GetProperty(“Source”); //獲取Source屬性
RangeAttribute [] attributes =
property.GetCustomAttributes(typeof(Attribute), true)
as RangeAttribute []; //獲取Range屬性集合
//遍歷集合對(duì)屬性進(jìn)行驗(yàn)證
foreach(var item in attribute){
int value = (int)property.GetValue(this, null);
if(value < item.Min || value > item.Max){
result = false;
}
}
return result;
}



那么再回過(guò)頭看先前的測(cè)試,我們可以發(fā)現(xiàn),測(cè)試成功運(yùn)行了(相關(guān)代碼見附帶項(xiàng)目的Leven.Validate01和test項(xiàng)目Validate01Test.cs).

我們?cè)诳茨壳暗拇a,現(xiàn)在我們能測(cè)試Source,如果我們的Student類中還有一項(xiàng)Age,范圍為6-150呢,那么Student中加上如下代碼:

[Range(6, 150, "學(xué)生年齡必須在{0}和{1}之間.")]
public int Age { get; set; }
那么我們的Validate方法是否能正確驗(yàn)證呢?為了驗(yàn)證結(jié)果,我們重新編寫測(cè)試:

[TestMethod()]
public void ValidateTest() {
Student student = new Student() {
Source = 80,
Age = 0
};
bool validateResult = student.Validate();
Assert.IsFalse(validateResult);
student.
validateResult = student.Validate();
}



執(zhí)行測(cè)試,很遺憾,測(cè)試無(wú)法通過(guò)了.我們可以再看看Validate方法,可以發(fā)現(xiàn),其中只對(duì)Source屬性進(jìn)行了驗(yàn)證,那么我們可以想辦法修改代碼,讓其能對(duì)Age和Source方法同時(shí)驗(yàn)證。

public bool Validate() {
bool result = true;
Type type = this.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (var property in properties) {
RangeAttribute[] attributes =
property.GetCustomAttributes(typeof(RangeAttribute), true) as RangeAttribute[];
foreach (var item in attributes) {
int value = (int)property.GetValue(this, null);
if (value < item.Min || value > item.Max) {
result = false;
}
}
}
return result;
}



修改過(guò)的方法中將遍歷所有的屬性,然后進(jìn)行驗(yàn)證,這時(shí)候再次運(yùn)行測(cè)試,生動(dòng)的綠色代表我們重新獲得了成功。

下面我們?cè)俅慰紤]新的可能情況,如果Student需要一個(gè)Name屬性,這是一個(gè)必須字段.我們考慮新增一個(gè)RequiredAttribute來(lái)實(shí)現(xiàn)該功能,該部分代碼如下(參見項(xiàng)目Leven.Validate03):

[AttributeUsage(AttributeTargets.Property)]
public class RequiredAttribute : Attribute {
public bool IsRequired { get; set; }
public string Message { get; set; }
public RequiredAttribute(string message) {
IsRequired = true;
Message = message;
}
}



然后修改Student部分,新增下面部分:

[Required]
public string Name { get; set; }
再次修改測(cè)試代碼:

[TestMethod()]
public void ValidateTest() {
Student student = new Student() {
Age = 20,
Source = 89,
Name = string.Empty
};
bool validateResult = student.Validate();
Assert.IsFalse(validateResult);
}



執(zhí)行測(cè)試,結(jié)果失敗了.查看原因,顯然可以看到,是Validate方法中

RangeAttribute[] attributes =property.GetCustomAttributes(typeof(RangeAttribute), true) as RangeAttribute[];

只驗(yàn)證了RangeAttribute,那針對(duì)我們加入的RequiredAttribute自然是無(wú)能為力了,為了能驗(yàn)證RequiredAttribute,我們?cè)俅涡薷牧舜a:

public bool Validate() {
bool result = true;
bool requiredResult = true;
Type type = this.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (var property in properties) {
RangeAttribute[] attributes =
property.GetCustomAttributes(typeof(RangeAttribute), true)
as RangeAttribute[]; //獲取RangeAttribute集合
RequiredAttribute[] requiredAttributes =
property.GetCustomAttributes(typeof(RequiredAttribute), true)
as RequiredAttribute[]; //獲取RequiredAttribute集合
//遍歷RangeAttribute進(jìn)行驗(yàn)證
foreach (var item in attributes) {
int value = (int)property.GetValue(this, null);
if (value < item.Min || value > item.Max) {
result = false;
}
}
//遍歷RequiredAttr進(jìn)行驗(yàn)證
foreach (var item in requiredAttributes) {
object value = property.GetValue(this, null);
if (value is string) {
if (String.IsNullOrEmpty((value as string))) {
requiredResult = false;
}
} else {
if (value == null) {
requiredResult = false;
}
}
}
}
return result && requiredResult;
}



這次的代碼量增加了不少,不過(guò)經(jīng)過(guò)我們的不懈努力,測(cè)試再一次通過(guò)了,但是,我們?cè)俅位貋?lái)查看驗(yàn)證部分的代碼,不難發(fā)現(xiàn)一個(gè)問(wèn)題,每次我們新增了驗(yàn)證Attribute之后都必須手動(dòng)在Validate方法中增加響應(yīng)的代碼,目前我們還只有兩個(gè)Attribute,如果一個(gè)系統(tǒng)中有20甚至200個(gè)Attribute(當(dāng)然只是打個(gè)比方),該方法的長(zhǎng)度恐怕將是個(gè)恐怖的數(shù)字,這樣的方法勢(shì)必?zé)o比丑陋。

到此,關(guān)于“MVC下ASP.NET的表單驗(yàn)證的實(shí)現(xiàn)方法”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

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

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI