本文將延續上一篇還沒講完的Model Validation,
繼續介紹ASP.Net Core MVC中自訂及遠端驗證的使用方式。
自訂驗證
雖然預設已有許多實用的[ValidationAttribute]
,
但難免還是會遇到需要自訂驗證的時候。
這個部分跟ASP.Net MVC5沒有太大的改變,
透過繼承ValidationAttribute
可以幫我們實作自訂的後端驗證,
即可迅速的打造一個屬於自己的[ValidationAttribute]
。
因為預設並沒有提供判斷日期先後的Attribute,
所以筆者下方來實作一個[DateAfter]
。
DateAfterAttribute.cs
public class DateAfterAttribute : ValidationAttribute
{
private DateTime start;
public DateAfterAttribute(string dateString, string format = "yyyy/MM/dd")
{
start = DateTime.ParseExact(dateString, format, null);
}
public override bool IsValid(object value)
{
var date = (DateTime)value;
if (date.Ticks > start.Ticks)
{
return true;
}
return false;
}
}
其實步驟相當簡單
首先繼承ValidationAttribute
抽象類別,
複寫Valid()
方法後就完成一半了。
要注意建構子中可定義使用時所需傳入的參數,
如[DateAfter("2020/1/1")]
,
建構子中第二個參數foramt
使用預設值的方式,
可使日期格式較具彈性變化。
Valid()
中的參數value為前端表單欄位中要驗證的值,
因為型別為object所以記得要轉型。
使用時可以省略Attribute字樣(DataAfterAttribute),
最後來把它掛到要驗證的屬性上。
public class Book
{
[BindRequired]
public int Id { get; set; }
[Required]
public string Title{ get; set; }
[DateAfter("2020/1/1", ErrorMessage = "your {0} should after 2020/1/1")]
public DateTime PublishDate { get; set; }
}
測試結果如下。
要加入自訂的前端驗證步驟會稍稍麻煩一點,
首先要實作 IClientValidator
介面,
我們來修改上面的DateAfterAttribute
。
public class DateAfterAttribute : ValidationAttribute, IClientModelValidator
{
private DateTime start;
public DateAfterAttribute(string dateString, string format = "yyyy/MM/dd")
{
start = DateTime.ParseExact(dateString, format, null);
}
public override bool IsValid(object value)
{
var date = (DateTime)value;
if (date.Ticks > start.Ticks)
{
return true;
}
return false;
}
public void AddValidation(ClientModelValidationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
//方式一
MergeAttribute(context.Attributes, "data-val", "true");
MergeAttribute(context.Attributes, "data-val-publishdate", "your publishdate should after 2020/12/30(前端驗證)");
//方式二
//context.Attributes["data-val"] = "true";
//context.Attributes["data-val-publishdate"] = "your publishdate should after 2020/12/30(前端驗證)";
}
private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
{
if (attributes.ContainsKey(key))
{
return false;
}
attributes.Add(key, value);
return true;
}
}
AddValidation
方法只是在定義前端欄位的觸發條件及錯誤訊息,
盡量按照data-val-{property_name}
的格式,
其中{property_name}要與前端設定的script相符。
除了透過MergeAttribute的方法,
也可以直接針對Context.Attributes
操作(IDictionary)。
最後要在前端.cshtml加上一小段script。
@section scripts{
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
<script>
$.validator.addMethod("publishdate",
function (value, element, param) {
var date = new Date(value);
return date >new Date('2020/12/30');
});
$.validator.unobtrusive.adapters.addBool("publishdate");
</script>
}
測試結果
遠端驗證
遠端驗證(Remote)是什麼呢?
它是一種很像前端的後端驗證。
在執行過程不仔細觀察你會以為它是前端驗證(因為不會閃一下),
其原理是藉ajax方式與後端溝通。
常用於「檢查欄位名稱是否與資料庫重複」。
透過掛上[Remote]
就可以簡單完成,
驗證過程會呼叫遠端的Action,
最後透過回傳的Json格式比對驗證結果。
接著繼續針對Book修改,
假設書名(Title)是不能夠重複的,
我們這部分透過遠端驗證來實現。
Book.cs
public class Book
{
[BindRequired]
public int Id { get; set; }
[Remote(action: "CheckRepeatTitle", controller: "Sample")]
[Required]
public string Title{ get; set; }
[DateAfter("2020/12/30", ErrorMessage = "your {0} should after 2020/12/30")]
public DateTime PublishDate { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
最後在SampleController中CheckRepeatTitle實作方法。
public IActionResult CheckRepeatTitle(string Title)
{
//Check title repeat state from database
var isBookTitleRepeat = true;
if (isBookTitleRepeat)
{
return Json($"{Title} is already in use.");
}
return Json(true);
}
大功告成後來測試一下結果。
遠端驗證使用起來其實非常爽,
如有需遠端驗證更進階應用的朋友可參考MSDN。
驗證的部分就先介紹到這邊,
如果內容有錯誤的在麻煩各位大神指正。
參考
https://docs.microsoft.com/zh-tw/aspnet/core/mvc/models/validation?view=aspnetcore-2.1
http://www.binaryintellect.net/articles/d80b2b90-847b-4c5b-90ac-c2db18e131be.aspx