ASP.NET MVC 表單驗證

ASP.NET MVC 框架驗證每一個傳遞給操做的數據是否有效,控制器操做能夠經過查詢ModelState來檢查請求是否有效,例如,保存有效數據到數據庫、後綴返回包含錯誤提示信息的原始表單給用戶。
這裏是AuctionsController.Create操做,用於判斷ModelState的有效性後進行「保存或者返回」 操做:數據庫

[HttpPost]
public ActionResult Create(Auction auction)
{
if(ModelState.IsValid)
{
var db = new EbuyDataContext();
db.Auction.Add(auction);
db.SaveChanges();
return RedirecToAction("Index");
}

return View(auction);
}

 

假設咱們的交易將持續至少一天時間,換句話說,交易的截止日期比當前的日期多一天。AuctionsController.Create操做能夠在保存以前驗證這個邏輯,固然在錯誤的時候給出提示信息:服務器

[HttpPost]
public ActionResult Create(Auction auction)
{

if(auction.EndTime <= DateTime.Now.AddDays(1))
{
ModelState.AddModelError(
"EndTime",
"Auction must be at least one day long"
);
}
if(ModelState.IsValid)
{
var db = new EbuyDataContext();
db.Auction.Add(auction);
db.SaveChanges();
return RedirecToAction("Index");
}

return View(auction);
}

 

這個方法確實有效,可是它沒有分離應用程序的關注點,控制器不該該包含這種業務邏輯,該業務邏輯屬於模型,因此要把業務邏輯移到模型裏。框架

使用數據聲明指定業務規則;
確保數據有效性(數據驗證)是開發人員必須面對的問題。一般狀況下,開發人員都是儘量藉助現有的框架來完成數據驗證工做。
這個需求很是廣泛,實際上,微軟提供了很是高效、便捷的數據驗證API,稱爲數據標註,屬於.NET框架的核心部分;學習

ASP.NET MVC 模型綁定提供了數據標記支持,不須要任何額外的配置,爲了學習ASP.NET MVC數據標記,咱們來看Auction類的驗證應用過程,爲了使用驗證邏輯,首先要考慮什麼是指望的Auction屬性值。哪些字段是必須的? 哪些字段必須在特定的範圍內纔算有效?ui

必填字段
由於auction 的Title 和Description對出售的商品相當重要,因此要給這兩個屬性標記RequiredAttribute,以便驗證數據的有效性;spa

[Required]
public string Title{get;set;}

[Required]
public string Description{get;set;}

 

除了標記字段爲必須的(Required)外,還能夠確保字符長度知足了最短長度的StringLengthAttribute屬性標記的要求,例如,若是決定了auction標題的長度最多50個字符,就能夠經過這個屬性來強化控制:code

[Required,StringLength(50)]
public string Title{get;set;}

若是用戶提交Title長度超過50個字符,ASP.NET MVC 模型驗證就會失敗。orm

驗證範圍:
接下來要考慮商品的起始價格:由StartPrice屬性表示,使用decimal類型,由於decimal是一個值類型,StartPrice默認爲0,因此就不必標記爲必填字段,可是交易的起始價格有個邏輯超過了必填字段的範圍,由於這個邏輯值,永遠不能爲負值,負值意味着賣家一開始就是欠帳的!爲了處理這個問題,須要使用RangeAttribute屬性來標記StartPrice字段,最小值是1.由於RangeAttribute須要一個最大值,因此能夠指定一個最大值做爲上限:blog

[Range(1,1000]
public decimal StartPrice{get;set;}

這個例子的區間使用了double類型,RangeAttribute標記屬性還有一個重載(Range(Type type,string min,string max))能夠知足任何實現了IComparable的類型。最好的例子就是日期範圍的驗證,例如,確保日期晚於某個特定的時間點:ip

[Range(typeof(DateTime),"1/1/2015","12/31/9999")]
public DateTime EndTime{get;set;}

這個例子確保EndTime屬性的值晚於2015年1月1日。
備註:.NET標記屬性參數必須是編譯時的值,在運行時沒法修改,並且不容許使用像DateTime.Now這樣的值來設置範圍,必須使用固定的日期,好比1/1/1/2015。
雖然沒法保證之後的日期有效,可是至少能夠保證目前的設置在有效的日期範圍內。

自定義錯誤信息:
最後要重點提到的是,數據標記提供了ErrorMessage屬性,能夠指定返回給用戶的錯誤信息,而不是由Data Annotations API生成的默認信息。如今把使用數據標記屬性的模型都指定值。

下面的類應該包含了上面討論的全部數據標記狀況:

public class Auction
{
[Required]
[StringLength(50,ErrorMessage="Title cannot be longer than 50 characters")]
public string Title{get;set;}

[Required]
public string Description{get;set;}

[Range(1,1000,ErrorMessage="The auction's starting price must be at least 1")]
public decimal StartPrice{get;set;}

public decimal CurrentPrice{get;set;}
public DateTime EndTime{get;set;}
}

既然模型裏已經定義了全部的驗證邏輯,那麼就再看看控制器和視圖是如何返回錯誤信息給用戶的。

顯示驗證錯誤:
能夠經過在Create操做裏設置斷點來查看驗證規則,只要提交無效的值,而後觀察ModelState屬性來驗證錯誤是什麼就能夠了,事實上,控制器返回Create視圖,而不是保存新交易數據,這偏偏證實了驗證規則的正確性以及驗證框架的有效性。雖然「Create」視圖顯示了無效紅邊框,但仍是沒返回任何錯誤提示信息來明確告訴用戶哪裏錯了,因此,咱們須要注意這個問題。
這是顯示Title屬性的代碼:

<p>
@Html.LabelFor(model=>model.Title)
@Html.EditorFor{model=>model.Title}
@ViewData.ModelState["Title"]
</p>

咱們須要作的就是添加與Title相關的驗證信息。最簡單的方式就是查看ModelState----經過View Data.ModelState和ViewData.ModelState["Title"] 返回的與Title屬性相關的錯誤提示信息。

咱們能夠迭代這個集合把錯誤信息渲染到頁面上,代碼以下:

<p>
@Html.LabelFor(model=>model.Title)
@Html.EditorFor{model=>model.Title}
@foreach(var error in ViewData.ModelState["Title"].Errors)
{
<span class="error">@error.ErrorMessage</span>
}
</p>

雖然這個方法不錯,可是ASP.NET MVC提供了更好的方法來渲染特定屬性的錯誤提示信息:Html.ValidationMessage(string modelName)幫助方法。它可讓咱們省去上面複雜的循環代碼,只須要一行調用代碼就能夠達到一樣的效果:
@Html.ValidationMessageFor(model=>model.Title)
爲模型裏的每一個屬性都添加調用Html.ValidationMessage()方法的代碼。ASP.NET MVC會在相關的控件右邊渲染出與驗證有關的錯誤提示信息。
除了使用屬性級別的Html.ValidationMessage()幫助方法外,ASP.NET MVC也提供了Html.ValidationSummary()。它能夠幫助咱們在一個地方渲染顯示驗證異常信息(例如,表單的頂部)。給用戶一個摘要提示信息,以方便用戶修正錯誤,正確提交表單。
這個幫助方法使用起來也至關簡單,只須要在想調用它的地方加一行代碼便可:

@using(Html.BeginForm())
{
@Html.ValidationSummary()
<p>
@Html.LabelFor(model=>model.Title)
@Html.EditorFor{model=>model.Title}
@Html.ValidationMessageFor(model=>model.Title)
</p>
<!--表單的其他字段-->
}

當用戶提交無效的值時,咱們能夠在兩個地方看到錯誤提示信息,即頂部的彙總信息(調用Html.ValidationSummary())和控件後邊的錯誤提示信息(調用Html.ValidationMessage()),

若是想避免重複顯示錯誤信息,則能夠修改調用Html.ValidationMessage()的代碼,指定更短的自定義錯誤提示信息,好比簡單的星號*,以下:

<p>
@Html.LabelFor(model=>model.Title)
@Html.EditorFor{model=>model.Title}
@Html.ValidationMessageFor(model=>model.Title,"*")
</p>

下面是使用了驗證標籤後的Cteate視圖文件的全部代碼:

<h2>Create Aution</h2>
@using(Html.BeginForm())
{
@Html.ValidationSummary()

<p>
@Html.LabelFor(model=>model.Title)
@Html.EditorFor{model=>model.Title}
@Html.ValidationMessageFor(model=>model.Title,"*")
</p>

<p>
@Html.LabelFor(model=>model.Description)
@Html.EditorFor{model=>model.Description}
@Html.ValidationMessageFor(model=>model.Description,"*")
</p>

<p>
@Html.LabelFor(model=>model.StartPrice)
@Html.EditorFor{model=>model.StartPrice}
@Html.ValidationMessageFor(model=>model.StartPrice,"*")
</p>

<p>
@Html.LabelFor(model=>model.EndTime)
@Html.EditorFor{model=>model.EndTime}
@Html.ValidationMessageFor(model=>model.EndTime,"*")
</p>
}

目前展現的驗證都是在服務端代碼驗證,須要在服務器和客戶端之間進行幾次合的交互過程才能驗證數據的有效性,並返回渲染過的視圖效果。

 

下面演示下,我在代碼中的實現:

構成表單:

@using (Html.BeginForm("requestVM", "VM", FormMethod.Post, new { id = "RequestForm" }))
    {
        
        @Html.AntiForgeryToken()
        <h1 class="resource_title creat_resource">
            <input class="close" type="button" id="btnCancel" value=" " />新建資源</h1>
        <ul class="form_des vm form_des1">
            <li><span>@Html.LabelFor(m => m.vmName)</span>@Html.EditorFor(model => model.vmName)@*@Html.ValidationMessageFor(m=>m.vmName)*@</li>
            <li><span>@Html.LabelFor(m => m.vmUserName)</span>@Html.EditorFor(model => model.vmUserName)@*@Html.ValidationMessageFor(m=>m.vmUserName)*@</li>
            <li><span>@Html.LabelFor(m => m.vmUserPassword)</span>@Html.PasswordFor(model => model.vmUserPassword)@*@Html.ValidationMessageFor(m=>m.vmUserPassword)*@</li>
            <li><span>@Html.LabelFor(m => m.ConfirmPassword)</span>@Html.PasswordFor(model => model.ConfirmPassword)@*@Html.ValidationMessageFor(m=>m.ConfirmPassword)*@</li>

            <li><span>@Html.LabelFor(m => m.vmCloudID)</span>@Html.DropDownListFor(model => model.vmCloudID, ViewBag.CloudList as List<SelectListItem>)@*@Html.ValidationMessageFor(m=>m.vmTemplateID)*@</li>
            <li><span>@Html.LabelFor(m => m.vmSubNetID)</span><div id="divAzureSubNet"></div>@*@Html.ValidationMessageFor(m=>m.vmTemplateID)*@</li>

            <li><span>@Html.LabelFor(m => m.vmTemplateID)</span>@Html.DropDownListFor(model => model.vmTemplateID, ViewBag.TempList as List<SelectListItem>)@*@Html.ValidationMessageFor(m=>m.vmTemplateID)*@</li>
            <li><span>@Html.LabelFor(m => m.vmRoleSizeID)</span>@Html.DropDownListFor(model => model.vmRoleSizeID, ViewBag.RoleSizeList as List<SelectListItem>)@*@Html.ValidationMessageFor(m=>m.vmRoleSizeID)*@</li>
<!--後面省略-->

顯示錯誤信息:

 <div class="creat_error">@Html.ValidationMessageFor(m => m.vmName)@Html.ValidationMessageFor(m => m.vmUserName)@Html.ValidationMessageFor(m => m.vmUserPassword)@Html.ValidationMessageFor(m => m.ConfirmPassword)@Html.ValidationMessageFor(m => m.vmTemplateID)@Html.ValidationMessageFor(m=>m.vmCloudID)@Html.ValidationMessageFor(m => m.vmRoleSizeID)@Html.ValidationMessage("Operation")</div>

模型Model類的構建:

ublic class VirtualMachineCreateModel
    {
        [Required(ErrorMessage="請輸入資源名稱")]
        [RegularExpression(@"^(?!-)(?!.*?-$)[a-zA-Z][a-zA-Z0-9.-]{2,14}$", ErrorMessage = "資源名稱由字母、數字和中劃線組成,且以字母開頭以字母或數字結尾的長度爲3-15位")]
        [Display(Name = "資源名稱")]
        public string vmName { get; set; }

        [Exclude(ExcludeStr = "a|administrator|user|root", ErrorMessage = "用戶名不能爲:a,administrator,user,root")]
        [Required(ErrorMessage="請輸入用戶名")]
        [RegularExpression(@"^[a-zA-Z][a-zA-Z0-9.-]{0,19}$", ErrorMessage = "用戶名由字母、數字和中劃線組成,且以字母開頭的長度爲1-20位")]
        [Display(Name="用戶名")]
        public string vmUserName { get; set; }

        
        [Required(ErrorMessage="請輸入密碼")]
        [DataType(DataType.Password)]
        [RegularExpression(@"(?=^.{8,15}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$", ErrorMessage = "密碼需同時包含大、小寫字符,且至少包含一位數字或特殊字符。密碼長度8-15位。")]
        [Display(Name="密碼")]
        public string vmUserPassword { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "確認密碼")]
        [Compare("vmUserPassword", ErrorMessage = "密碼和確認密碼不匹配。")]
        public string ConfirmPassword { get; set; }

        //此處省略  「不少abc」;;;;;;
    }

 

但願對你有幫助;

相關文章
相關標籤/搜索