ASP.NET MVC中對Model進行分步驗證的解決方法
在我之前的文章:ASP.NET MVC2.0結合WF4.0實現用戶多步注冊流程中將一個用戶的注冊分成了四步,而這四個步驟都是在完善一個Model的信息,但是又分頁面填寫信息的,當時我加上ModelState.IsValid這句驗證代碼的時候,根本沒法通過驗證,因為在注冊的前面三步,注冊用戶的Model信息都沒填寫完整,而ModelState.IsValid是對一個實體的所有屬性進行判斷驗證的。當時很糾結,因為剛接觸Asp.net MVC,故沒有找到解決方案。這篇文章將給出解決的辦法。看下面需要驗證的Model的代碼如下:
{
[DisplayName("step")]
[Required(ErrorMessage = "You must select a step .")]
public int Step { get; set; }
//個人信息
[Required(ErrorMessage = "姓名不能為空")]
[StringLength(20, ErrorMessage = "姓名長度不能超過20個字符")]
public string Name { get; set; }
[RegularExpression(@"120|((1[0-1]|\d)?\d)", ErrorMessage = "年齡格式不對")]
public int? Age { get; set; }
//職位信息
[Required(ErrorMessage = "職位不能為空")]
public string Post { get; set; }
public int? Salary { get; set; }
//學歷信息
[Required(ErrorMessage = "畢業院校不能為空")]
public string University { get; set; }
public int? GraduationYear { get; set; }
//聯系信息
[Required(ErrorMessage = "郵件不能為空")]
[RegularExpression(@"^[a-z][a-z|0-9|]*([_][a-z|0-9]+)*([.][a-z|" + @"0-9]+([_][a-z|0-9]+)*)?@[a-z][a-z|0-9|]*\.([a-z]" + @"[a-z|0-9]*(\.[a-z][a-z|0-9]*)?)$", ErrorMessage= "郵件格式不正確")]
public string Email { get; set; }
public int? Mobile { get; set; }
public IEnumerable<SelectListItem> StepList { get; set; }
public UserViewModel()
{
var list = new List<SelectListItem>() {
new SelectListItem { Text = "(Select)" },
new SelectListItem { Value = "1", Text = "Step1" },
new SelectListItem { Value = "2", Text = "Step2" },
new SelectListItem { Value = "3", Text = "Step3" },
new SelectListItem { Value = "4", Text = "Step4" }
};
this.StepList = new SelectList(list, "Value", "Text");
}
}
實現:
這篇文章這種情況服務端和客戶端的驗證都會講到。為了簡化起見,這里我除去的WF的流程功能,直接用下拉框表示,當下拉框選擇step1表示填寫第一步注冊的信息,當下拉框選擇step2表示填寫第二步注冊的信息,當下拉框選擇step3表示填寫第三步注冊的信息,當下拉框選擇step4表示填寫第四步注冊的信息。寫得很啰嗦,但是這個很容易實現,我使用Jquery來顯示和隱藏下拉框對應的Step。Jquery代碼如下:
$(function () {
$.fn.enable = function () {
return this.show().removeAttr("disabled");
}
$.fn.disable = function () {
return this.hide().attr("disabled", "disabled");
}
var dllStep = $("#Step");
var step1 = $("#Step1,#Step1 input");
var step2 = $("#Step2,#Step2 input");
var step3 = $("#Step3,#Step3 input");
var step4 = $("#Step4,#Step4 input");
setControls();
dllStep.change(function () {
setControls();
});
function setControls() {
switch (dllStep.val()) {
case "1":
step1.enable();
step2.disable();
step3.disable();
step4.disable();
break;
case "2":
step1.disable();
step2.enable();
step3.disable();
step4.disable();
break;
case "3":
step1.disable();
step2.disable();
step3.enable();
step4.disable();
break;
case "4":
step1.disable();
step2.disable();
step3.disable();
step4.enable();
break;
case "":
step1.disable();
step2.disable();
step3.disable();
step4.disable();
break;
}
}
});
</script>
如下圖:
第一步:填寫姓名和年齡。
第二步:填寫職位和薪水。
第三步填寫:畢業院校和畢業時間。
第四步填寫:郵箱和電話。
為了實現這樣的驗證,我們可以將驗證的錯誤信息中移除不在當前步驟填寫的字段的錯誤信息,寫一個類InputValidationModelBinder繼承DefaultModelBinder并重載OnModelUpdated方法,將不必要的錯誤信息清除,代碼如下:
{
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var modelState = controllerContext.Controller.ViewData.ModelState;
var valueProvider = controllerContext.Controller.ValueProvider;
var keysWithNoIncomingValue = modelState.Keys.Where(x => !valueProvider.ContainsPrefix(x));
foreach (var key in keysWithNoIncomingValue)
modelState[key].Errors.Clear();
}
}
上面是服務端的代碼,對于客戶端,我們都知道asp.net MVC客戶端驗證時通過MicrosoftMvcValidation.js去實現的。看下面代碼。
2 var fields = this.fields;
3 var errors = [];
4 for (var i = 0; i < fields.length; i++) {
5 var field = fields[i];
6 if (!field.elements[0].disabled) {
7 var thisErrors = field.validate(eventName);
8 if (thisErrors) {
9 Array.addRange(errors, thisErrors);
10 }
11 }
12 }
13 if (this.replaceValidationSummary) {
14 this.clearErrors();
15 this.addErrors(errors);
16 }
17 return errors;
18 }
19 }
在第6行代碼加入了一句判斷:當頁面的元素沒有被disabled的時候才去驗證。好了這樣就實現了一次只對Model中的幾個屬性字段進行驗證。
運行:
asp.net mvc的驗證機制只對model中當前頁面的屬性進行驗證:
填寫正確通過驗證:
總結:本文解決了我之前遺留下來的一個問題。實現了在ASP.NET MVC中對Model進行多步驗證。希望對你有所幫助,如果你有更好的方法,歡迎給我留言。
留言列表