asp.net core系列之模型綁定和驗(yàn)證方法
一. 模型綁定
ASP.NET Core MVC 中的模型綁定,是將 HTTP 請求中的數(shù)據(jù)映射到 action方法參數(shù)。 這些參數(shù)可能是簡單類型的參數(shù),如字符串、整數(shù)或浮點(diǎn)數(shù),也可能是復(fù)雜類型的參數(shù)。 當(dāng) MVC 收到 HTTP 請求時(shí),它會(huì)將此請求路由定位到控制器的指定 action方法。默認(rèn)路由模板為 {controller=Home}/{action=Index}/{id?}
//例如:請求URL http://contoso.com/movies/edit/2 //映射到movies/edit/2 public IActionResult Edit(int? id)
上面Url請求對應(yīng)movies控制器下的Edit方法,該方法接受名為 id 的可選參數(shù)。MVC會(huì)將Edit中的id參數(shù)綁定到路由值中 具有相同名稱 的值。 URL 路由中的字符串不區(qū)分大小寫。
上面示例綁定的參數(shù)是簡單類型,如果參數(shù)是一個(gè)類,例如 Movie 類型,該類包含簡單和復(fù)雜類型作為屬性,MVC的模型綁定仍然可以很好地處理它。它使用反射和遞歸來遍歷尋找匹配的復(fù)雜類型的屬性(如:Collection、Dictionary)。
如果模型綁定失敗,MVC 不會(huì)引發(fā)錯(cuò)誤,參數(shù)值會(huì)是null。 如果HTTP 請求中的數(shù)據(jù)是用戶輸入的值,在action中應(yīng)使用 ModelState.IsValid 屬性檢查,不需要手動(dòng)去檢查。
注意:若要實(shí)現(xiàn)模型綁定,該類必須具有要綁定的公共默認(rèn)構(gòu)造函數(shù)和公共可寫屬性。 發(fā)生模型綁定時(shí),在使用公共默認(rèn)構(gòu)造函數(shù)對類進(jìn)行實(shí)例化后才可設(shè)置屬性。
模型綁定完成后,將發(fā)生模型驗(yàn)證。 對于絕大多數(shù)開發(fā)方案,默認(rèn)模型綁定效果極佳。還可以擴(kuò)展,如果有特殊需求,則可自定義內(nèi)置行為包括:模型綁定特性、全局自定義模型綁定和驗(yàn)證、綁定請求正文中的帶格式數(shù)據(jù)(JSON、XML 和許多其他格式)、還有高級篇中自定義模型綁定。這里不在說明,請查看文檔。
二.模型驗(yàn)證
在將數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫之前,應(yīng)用程序必須先驗(yàn)證數(shù)據(jù)。在 MVC 中,驗(yàn)證發(fā)生在客戶端和服務(wù)器上。
2.1 驗(yàn)證屬性
驗(yàn)證屬性是模型驗(yàn)證的一種方法, 概念上類似于對數(shù)據(jù)庫表中字段的驗(yàn)證, 驗(yàn)證屬性在屬性級別指定,下面是一個(gè)示例:
public class Movie
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Title { get; set; }
[ClassicMovie(1960)]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; }
[Range(0, 999.99)]
public decimal Price { get; set; }
[Required]
public Genre Genre { get; set; }
public bool Preorder { get; set; }
}
常用的內(nèi)置驗(yàn)證屬性包括: [ CreditCard] 信用卡格式、 [Compare]匹配兩個(gè)屬性、 [ EmailAddress] 郵件格式、 [ Phone] 電話格式、 [Range] 給定范圍內(nèi)、 [RegularExpression] 正則表達(dá)式、 [Required]必須屬性值、 [StringLength] 最大長度、 [Url] URL格式,還可以包括自定義驗(yàn)證屬性(例如 ClassicMovie )。 所有的內(nèi)置驗(yàn)證屬性 參考官網(wǎng)
2.2 自定義驗(yàn)證
上面的驗(yàn)證屬性適用于大多數(shù)驗(yàn)證需求。 但是,某些驗(yàn)證規(guī)則特定于你的業(yè)務(wù)。在 MVC 中創(chuàng)建自定義驗(yàn)證屬性很簡單。只需從 ValidationAttribute 繼承并重寫 IsValid 方法。 IsValid 方法采用兩個(gè)參數(shù),第一個(gè)是名為 value 的對象,第二個(gè)是名為 validationContext 的 ValidationContext 對象。 Value 引用自定義驗(yàn)證程序要驗(yàn)證的字段中的實(shí)際值。
/// <summary>
/// 自定義驗(yàn)證
/// </summary>
public class ClassicMovieAttribute : ValidationAttribute
{
private int _year;
/// <summary>
/// 驗(yàn)證規(guī)則值
/// </summary>
/// <param name="year"></param>
public ClassicMovieAttribute(int year)
{
_year = year;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
Movie movie = (Movie)validationContext.ObjectInstance;
//用戶不能將 1960 年以后發(fā)行的電影的流派設(shè)置為 Classic
if (movie.Genre == "Classic" && movie.ReleaseDate.Year > _year)
{
return new ValidationResult(GetErrorMessage());
}
return ValidationResult.Success;
}
private string GetErrorMessage()
{
return $"Classic movies must have a release year earlier than {_year}.";
}
}
運(yùn)行程序,ReleaseDate是1989年,Genre是Classic,點(diǎn)擊Save,驗(yàn)證是在服務(wù)端進(jìn)行,顯示錯(cuò)誤消息,沒有經(jīng)過前端js驗(yàn)證,如下所示:

2.3 客戶端js驗(yàn)證介紹
jQuery 非介入式驗(yàn)證腳本是一個(gè)自定義微軟前端庫,建立在流行的 jQuery Validate 插件??蛻舳蓑?yàn)證原理是: MVC 的標(biāo)記幫助程序和 HTML 幫助程序則能夠使用模型屬性中的驗(yàn)證特性和類型元數(shù)據(jù),呈現(xiàn)需要驗(yàn)證的表單元素中的 HTML 5 data- 屬性。MVC 為內(nèi)置模型屬性和自定義模型屬性生成 data- 屬性。然后,jQuery 非介入式驗(yàn)證分析 data- 屬性并將邏輯傳遞給 jQuery Validate,從而將服務(wù)器端驗(yàn)證邏輯有效地“復(fù)制”到客戶端。 可以使用相關(guān)標(biāo)記幫助程序在客戶端上顯示驗(yàn)證錯(cuò)誤。
下面示例表單中,asp- 標(biāo)記幫助程序代碼如下:
<div class="form-group"> <label asp-for="ReleaseDate" class="control-label"></label> <input asp-for="ReleaseDate" class="form-control" /> <span asp-validation-for="ReleaseDate" class="text-danger"></span> </div>
標(biāo)記幫助程序?qū)⑸梢韵聅ource html。請注意,HTML 輸出中的 data- 屬性與 ReleaseDate 屬性的驗(yàn)證特性相對應(yīng)。下面的 data-val-required 屬性包含在用戶未填寫發(fā)行日期字段時(shí)將顯示的錯(cuò)誤消息。jQuery 非介入式驗(yàn)證將此值傳遞給 jQuery Validate required() 方法,該方法隨后在隨附的 <span> 元素中顯示該錯(cuò)誤消息。
<form action="/Movies/Create" method="post">
<div class="form-horizontal">
<h4>Movie</h4>
<div class="text-danger"></div>
<div class="form-group">
<label class="col-md-2 control-label" for="ReleaseDate">ReleaseDate</label>
<div class="col-md-10">
<input class="form-control" type="datetime"
data-val="true" data-val-required="The ReleaseDate field is required."
id="ReleaseDate" name="ReleaseDate" value="" />
<span class="text-danger field-validation-valid"
data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
</div>
</div>
</div>
</form>
2.4 動(dòng)態(tài)表單添加驗(yàn)證
在創(chuàng)建動(dòng)態(tài)表單后,需要立即對其進(jìn)行分析。 例如,下面的代碼展示如何對通過 AJAX 添加的表單設(shè)置客戶端驗(yàn)證。
$.get({
url: "https://url/that/returns/a/form",
dataType: "html",
error: function(jqXHR, textStatus, errorThrown) {
alert(textStatus + ": Couldn't add form. " + errorThrown);
},
success: function(newFormHTML) {
//添加表單newFormHTML
var container = document.getElementById("form-container");
container.insertAdjacentHTML("beforeend", newFormHTML);
//驗(yàn)證第一個(gè)表單
var forms = container.getElementsByTagName("form");
var newForm = forms[forms.length - 1];
//分析表單的 data- 屬性
$.validator.unobtrusive.parse(newForm);
}
})
$.validator.unobtrusive.parse() 方法分析該選擇器內(nèi)表單的 data- 屬性。當(dāng)用戶填寫表單中的屬性值提交時(shí), 這些屬性的值傳遞到 jQuery Validate 插件中,以便表單展示所需的客戶端驗(yàn)證規(guī)則。
下面用一個(gè)簡單示例來說明:
(1) 創(chuàng)建dynamic-form-validate.js文件,模擬動(dòng)態(tài)生成表單,以及點(diǎn)擊(#idbtn)按鈕時(shí)驗(yàn)證:
var newFormHTML = "<form action=\"create\" method=\"post\">";
newFormHTML += "<div class=\"form-group\">";
newFormHTML += "<label asp-for=\"Title\" class=\"control- label\"></label>";
newFormHTML += "<input type=\"text\" data-val=\"true\" data-val-required=\"The Title field is required.\" id = \"Title\" name= \"Title\">";
newFormHTML += "<span class=\"text- danger field- validation - valid\" data-valmsg-for=\"Title\" data-valmsg-replace=\"true\"></span>";
newFormHTML += "</div>";
newFormHTML += "<div class=\"form-group\" >";
newFormHTML += "<input type=\"submit\" value=\"Save\" class=\"btn btn-primary\" />";
newFormHTML += "</div >";
newFormHTML += "</form>";
$("#idbtn").click(function () {
var container = document.getElementById("form-container");
container.insertAdjacentHTML("beforeend", newFormHTML);
var forms = container.getElementsByTagName("form");
var newForm = forms[forms.length - 1];
//分析表單的 data- 屬性
$.validator.unobtrusive.parse(newForm);
});
(2) 新建create頁
@model StudyMVCDemo.Models.Movie
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<div class="row">
<input value="動(dòng)態(tài)加載表單" type="button" id="idbtn" />
<div id="form-container" class="col-md-4">
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script src="~/js/dynamic-form-validate.js"></script>
}
運(yùn)行程序,點(diǎn)擊"動(dòng)態(tài)加載表單" 調(diào)用js將html表單添加到form-container元素容器中,點(diǎn)擊save提示該字段不能為空,效果如下所示:

2.5 動(dòng)態(tài)控件添加驗(yàn)證
當(dāng)向表單動(dòng)態(tài)添加控件(比如: <input/> 和 <select/> )時(shí),需要更新表單上的驗(yàn)證規(guī)則。做法是應(yīng)當(dāng)先刪除現(xiàn)有的驗(yàn)證數(shù)據(jù),然后重新分析整個(gè)表單,如下js代碼所示:
$.get({
url: "https://url/that/returns/a/control",
dataType: "html",
error: function(jqXHR, textStatus, errorThrown) {
alert(textStatus + ": Couldn't add control. " + errorThrown);
},
success: function(newInputHTML) {
//向表單動(dòng)態(tài)添加Input控件
var form = document.getElementById("my-form");
form.insertAdjacentHTML("beforeend", newInputHTML);
//移除現(xiàn)有的驗(yàn)證
$(form).removeData("validator") // Added by jQuery Validate
.removeData("unobtrusiveValidation"); // Added by jQuery Unobtrusive Validation
//重新分析整個(gè)表單
$.validator.unobtrusive.parse(form);
}
})
2.6 IClientModelValidator
在上面2.2自定義驗(yàn)證中,繼承了ValidationAttribute進(jìn)行服務(wù)端驗(yàn)證,還可以結(jié)合實(shí)現(xiàn)IClientModelValidator接口實(shí)現(xiàn)客戶端驗(yàn)證,該接口用來控制要添加哪些 data- 屬性。實(shí)現(xiàn)接口如下所示:
/// <summary>
/// 自定義驗(yàn)證
/// </summary>
public class ClassicMovieAttribute : ValidationAttribute,IClientModelValidator
{
private int _year;
/// <summary>
/// 年份參考值
/// </summary>
/// <param name="year"></param>
public ClassicMovieAttribute(int year)
{
_year = year;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
Movie movie = (Movie)validationContext.ObjectInstance;
//用戶不能將 1960 年以后發(fā)行的電影的流派設(shè)置為 Classic
if (movie.Genre == "Classic" && movie.ReleaseDate.Year > _year)
{
return new ValidationResult(GetErrorMessage());
}
return ValidationResult.Success;
}
private string GetErrorMessage()
{
return $"Classic movies must have a release year earlier than {_year}.";
}
public void AddValidation(ClientModelValidationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
MergeAttribute(context.Attributes, "data-val", "true");
MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());
var year = _year.ToString(CultureInfo.InvariantCulture);
MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
}
private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
{
if (attributes.ContainsKey(key))
{
return false;
}
attributes.Add(key, value);
return true;
}
}
生成的源html代碼如下所示:
<input class="form-control" type="date" data-val="true" data-val-classicmovie="Classic movies must have a release year earlier than 1960." data-val-classicmovie-year="1960" data-val-required="The ReleaseDate field is required." id="ReleaseDate" name="ReleaseDate" value="1989-02-12">
在上面雖然實(shí)現(xiàn)了IClientModelValidator接口,但jQuery不了解規(guī)則或消息,還需要自定義 classicmovie 客戶端驗(yàn)證方法,添加到j(luò)Query validator 對象。腳本如下所示:
//添加驗(yàn)證方法
$.validator.addMethod('classicmovie',function (value, element, params) {
//value ,是當(dāng)前驗(yàn)證的元素的值。
//element 元素本身。
//params 是傳入的參數(shù)(options.rules)
var genre = $("#form1").find("#Genre").val(),
year = params[0],
date = new Date(value);
if (genre.length > 0 && genre === 'Classic') {
// Since this is a classic movie, invalid if release date is after given year.
return date.getFullYear() <= year;
}
return true;
});
//注冊一個(gè)適配器,參數(shù)1是適配器名稱,參數(shù)2是驗(yàn)證規(guī)則的名稱
$.validator.unobtrusive.adapters.add('classicmovie',['year'],function (options) {
//適配器規(guī)則綁定到j(luò)query validation上面
options.rules['classicmovie'] = [parseInt(options.params['year'])];
options.messages['classicmovie'] = options.message;
});
運(yùn)行程序,ReleaseDate是1989年,Genre是Classic,點(diǎn)擊Save,客戶端驗(yàn)證返回false,提示錯(cuò)誤信息,如下所示:

參考文獻(xiàn)
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- ASP.NET?Core?模型驗(yàn)證消息的本地化新姿勢詳解
- ASP.NET?Core?6.0?基于模型驗(yàn)證的數(shù)據(jù)驗(yàn)證功能
- ASP.NET?Core中Cookie驗(yàn)證身份用法詳解
- asp.net core3.1cookie和jwt混合認(rèn)證授權(quán)實(shí)現(xiàn)多種身份驗(yàn)證方案
- asp.net core配合vue實(shí)現(xiàn)后端驗(yàn)證碼邏輯
- [Asp.Net Core]用Blazor Server Side實(shí)現(xiàn)圖片驗(yàn)證碼
- ASP.NET Core實(shí)現(xiàn)自定義WebApi模型驗(yàn)證詳解
- ASP.NET Core WebApi中使用FluentValidation驗(yàn)證數(shù)據(jù)模型的方法
相關(guān)文章
asp.net 產(chǎn)生唯一隨機(jī)碼的方法分析
現(xiàn)在的WEB中經(jīng)常會(huì)需要產(chǎn)生一些邀請碼、激活碼。需要是唯一并且隨機(jī)的。下面總結(jié)下一些常用的產(chǎn)生隨機(jī)碼的方法,并分享自己的1個(gè)方法.2010-10-10
MVC使用Controller代替Filter完成登錄驗(yàn)證(Session校驗(yàn))學(xué)習(xí)筆記5
這篇文章主要介紹了MVC使用Controller代替Filter完成登錄驗(yàn)證即Session校驗(yàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
ASP.NET MVC 開發(fā)微信支付H5的實(shí)現(xiàn)示例(外置瀏覽器支付)
這篇文章主要介紹了ASP.NET MVC 開發(fā)微信支付H5的實(shí)現(xiàn)示例(外置瀏覽器支付),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
ASP.NetCore使用Swagger實(shí)戰(zhàn)
這篇文章主要介紹了ASP.NetCore使用Swagger實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
VS2015在升級到Update2之后運(yùn)行Cordova項(xiàng)目異常的解決方案
這篇文章主要介紹了VS2015在升級到Update2之后運(yùn)行Cordova項(xiàng)目異常的解決方案的相關(guān)資料,需要的朋友可以參考下2016-07-07
靜態(tài)gb2312編碼在項(xiàng)目傳值出現(xiàn)中文亂碼現(xiàn)象
參考的美工靜態(tài)頁面是gb2312格式的,當(dāng)此編碼拿到項(xiàng)目中后,utf-8編碼的系統(tǒng),加載頁面時(shí),會(huì)出現(xiàn)樣式問題,比如不能正常居中等2013-06-06
ASP.NET?Core?實(shí)現(xiàn)自動(dòng)刷新JWT?Token
這篇文章主要介紹了ASP.NET?Core?實(shí)現(xiàn)自動(dòng)刷新JWT?Token,通過增加??refresh_token??,客戶端使用refresh_token去主動(dòng)刷新JWT?Token,下文具體操作過程需要的小伙伴可以參考一下2022-04-04

