ASP.NET Core 模型验证系列一

什么是模型验证? 模型验证是给模型属性提供一种规则,并且可以验证模型属性的值,以至于他们是合法的,如果这些值不合法,给客户显示一些容易理解的错误并且帮助客户修改正这个问题

模型验证分为两类:

1 服务器端验证

2 客户端验证

1 ASP.NET Core ModelState

什么是ModelState ? ModelState 是一个键值对的集合包含了模型绑定和验证过程中发生的错误,例如-使用一个字符串类型值赋值给Int整数类型 ,ModelState 将会给予一个错误

做模型验证之前我们首先得两个成员:

 AddModelError() 方法

 ModelState.IsValid 属性

1.1 AddModelError()方法

AddModelError()方法记录指定的属性模型验证错误

AddModelError(property, message);

property –实体类的一个属性

message –指定属性的错误消息

1.2 ModelState.IsValid属性

如果模型类中所有的属性的值都可用,ModelState.IsValid返回true,即在ModelState中有错误, 返回false,我们在IF ELSE 代码块如下:

if (ModelState.IsValid)
{
... do something
}
else
{
... do something
}

2 模型验证的例子

现在我们使用JobApplication表单做一个模型验证的例子,在这个表单中使用了不同类型的输入控件:

(1) 姓名 输入控件

(2) 出生日期输入控件

(3) 性别是一个radio button

(4) Experience是选择控件

(5) 接受条款是checkbox

因此,首先使用下面代码创建一个JobApplication.cs 类 在应用程序Models文件夹下

namespace AspNetCore.ModelValidation.Models
{
    public class JobApplication
    {
        public string Name { get; set; }
        public DateTime DOB { get; set; }
        public string Sex { get; set; }
        public string Experience { get; set; }
        public bool TermsAccepted { get; set; }
    }
}

JobApplication类定义了不同的属性,为我们模型验证做测试,创建2个视图在Views->job 文件夹下,他们分别是:

Index.cshtml

@model JobApplication
@{
    ViewData["Title"] = "Job Application";
}
<h2>Job Application</h2>
<form class="m-1 p-1" method="post">
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="Name" class="control-label"></label>
        </div>
        <div class="col-sm-11">
            <input asp-for="Name" class="form-control" />
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="DOB" class="control-label"></label>
        </div>
        <div class="col-sm-11">
            <input asp-for="DOB" type="text" asp-format="{0:d}" class="form-control" />
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="Sex" class="control-label"></label>
        </div>
        <div class="col-sm-1">
            <input asp-for="Sex" type="radio" value="M" class="form-check" />男
        </div>
        <div class="col-sm-1">
            <input asp-for="Sex" type="radio" value="F" class="form-check" />女
        </div>
        <div class="col-sm-9">
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="Experience" class="control-label"></label>
        </div>
        <div class="col-sm-11">
            <select asp-for="Experience" class="form-control">
                <option value="选择">选择</option>
                <option value="0">新手</option>
                <option value="1">0-1 年</option>
                <option value="2">1-2 年</option>
                <option value="3">2-3 年</option>
                <option value="4">3-4 年</option>
                <option value="5">4-5 年</option>
            </select>
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
        </div>
        <div class="col-sm-1">
            <input asp-for="TermsAccepted" class="form-label" />
        </div>
        <div class="col-sm-10">
            <label asp-for="TermsAccepted" class="form-check-label">
                我接受条款 & 条件
            </label>
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-11 offset-sm-1">
            <button type="submit" class="btn btn-primary">提交</button>
        </div>
    </div>
</form>

这个视图包含一个Job申请表单,用户填充详细信息并且通过点击Submit提交表单

Accepted.cshtml

@model JobApplication
@{
    Layout = "_Layout";
    ViewData["Title"] = "接受";
}
<h2>接受</h2>
<table class="table table-bordered">
    <tr>
        <th>姓名:</th>
        <td>@Model.Name</td>
    </tr>
    <tr>
        <th>出生日期:</th>
        <td>@Model.DOB.ToString("d")</td>
    </tr>
    <tr>
        <th>性别:</th>
        <td>@Model.Sex</td>
    </tr>
    <tr>
        <th>工作经验:</th>
        <td>@Model.Experience</td>
    </tr>
    <tr>
        <th>条款:</th>
        <td>@Model.TermsAccepted</td>
    </tr>
</table>
<a class="btn btn-success" asp-action="Index">返回</a>

这个视图在html表格内将显示客户端提交的值,接下来创建一个控制器文件叫JobController.cs在内部添加2个方法,他们是:

(1) HttpGet版本的Index - 给用户提供输入的选项

(2) HttpPost版本的Index- 处理用户提交的数据

用户提交的数据将呈现Accepted视图table内,HTTP POST版本的Index方法通过模型绑定技术接受用户在表单中填充的值,代码如下:

using AspNetCore.ModelValidation.Models;
using Microsoft.AspNetCore.Mvc;
namespace AspNetCore.ModelValidation.Controllers
{
    public class JobController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
        [HttpPost]
        public IActionResult Index(JobApplication jobApplication)
        {
            return View("Accepted", jobApplication);
        }
    }
}

现在运行应用程序并且进入URL – /Job,你将发现Job申请表单,这个表单看上去很Nice,但是没有做模型验证

df37948e35573750c50a150a4494b232.png

将下面值输入到控件中:

1. 姓名– Donald

2. 出生日期– 12-24-1986

3. 性别– 不输入任何值,保持原样

4. 经验– 不输入任何值,保持原样

5. 我接受条款和条件 –不输入任何值,保持原样

当我们点击提价按钮时,输入的值将会显示在浏览器中:

0b43b7bc71d9f656a0669c4d6296b76f.png

这里有一些缺陷,我们填充出生日期是12-24-1986但是现在显示 01-01-0001,这是因为出生日期要求的是DD-MM-YYYY格式日期,但是我们输入的是MM-DD-YYYY格式,因此这个值没有被绑定到action方法的参数JobApplication对象的出生日期属性上,因此这将显示时间的默认值01-01-0001

这个表单也没有强迫用户选择性别、经验、条款,为了阻止用户输入错误的出生日期,并且强迫他在表单输入所有信息,我们使用模型验证过程

2.1 提交模型验证代码

现在,我们将使用模型验证手段防止用户在表单中输入未验证的值,在这个例子中,我们指定ASP.NET Core 服务器端的验证,修改HttpPost版本的Index方法,代码如下:

using AspNetCore.ModelValidation.Models;
using Microsoft.AspNetCore.Mvc;
namespace AspNetCore.ModelValidation.Controllers
{
    public class JobController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
        [HttpPost]
        public IActionResult Index(JobApplication jobApplication)
        {
            if (string.IsNullOrEmpty(jobApplication.Name))
                ModelState.AddModelError(nameof(jobApplication.Name), "请输入用户名");
            if (jobApplication.DOB == Convert.ToDateTime("01-01-0001 00:00:00"))
                ModelState.AddModelError(nameof(jobApplication.DOB), "请输入出生日期");
            else if (jobApplication.DOB > DateTime.Now)
                ModelState.AddModelError(nameof(jobApplication.DOB), "出生日期不能大于当前时间");
            else if (jobApplication.DOB < new DateTime(1980, 1, 1))
                ModelState.AddModelError(nameof(jobApplication.DOB), "出生日期不能在1980年以前");
            if (string.IsNullOrEmpty(jobApplication.Sex))
                ModelState.AddModelError(nameof(jobApplication.Sex), "请选择性别");
            if (jobApplication.Experience.ToString() == "Select")
                ModelState.AddModelError(nameof(jobApplication.Experience), "请选择工作经验");
            if (!jobApplication.TermsAccepted)
                ModelState.AddModelError(nameof(jobApplication.TermsAccepted), "必须接受条款");
            if (ModelState.IsValid)
                return View("Accepted", jobApplication);
            else
                return View();
        }
    }
}

在上面代码中,验证JobApplication类每一个属性 ,确保用户在表单中输入正确的值,让我们接着讨论一下每个字段验证的值

2.2 姓名属性

代码-if (string.IsNullOrEmpty(jobApplication.Name)) 检查 如果用户没有在name控件中填充名字,在这种情况下,代码- ModelState.AddModelError(nameof(jobApplication.Name), "请输入用户名");将执行,我们把验证姓名属性时发生的错误记录在ModelState

2.3 出生日期属性

针对出生日期属性有3个检查:

条件 1 - 如果在字段中,用户没有输入出生日期或者提供了有个不可用的日期像"apple" ,会执行代码 – if (jobApplication.DOB == Convert.ToDateTime("01-01-0001 00:00:00")),当用户没有提供任何值的时候,日期属性将被提供一个默认值01-01-0001 00:00:00 

条件 2 - 如果用户提供的日期大于当前日期,它将通过下面代码检查-elseif (jobApplication.DOB > DateTime.Now)

条件 3 -如果用户提供出生日期在1980年以前,下面代码将执行- elseif (jobApplication.DOB < new DateTime(1980, 1, 1)),当检查失败时,提供容易理解的错误消息

2.4 性别属性

用户可以通过radio buttons 选择性别属性,如果用户没有选择性别,执行该代码检查

if (string.IsNullOrEmpty(jobApplication.Sex))

这种情况下,Sex 属性验证的错误消息会被记录到ModelState中,通过下面代码

ModelState.AddModelError(nameof(jobApplication.Sex), "请选择性别");

2.5 经验属性

在razor视图中提供了工作经验选择下拉框,默认值是Select,因此代码

if (jobApplication.Experience.ToString() == "Select")

确定用户在没有选择工作经验时,Experience属性对应的错误信息将被记录

2.6 接受条款属性

如果用户没有选择对应的接受条款,将会在ModelState中针对这个属性记录一条错误,代码-if (!jobApplication.TermsAccepted) ,最后,我们使用代码-ModelState.IsValid 做判断,当没有任何错误发生时,我们将返回接受视图并且提供jobApplication对象作为模型,如果ModelState.IsValid 返回false,那意味模型验证没有通过,因此我们能仅仅返回相同的视图,用户将看到错误,提示用户修改值

下面代码检查ModelState:

if (ModelState.IsValid)
    return View("Accepted", jobApplication);
else
    return View();

下面代码将在视图显示未验证的错误

3 检查HTML控件的形态

验证检查失败时模型绑定会为HTML控件添加名字为input-validation-error的CSS类,打开URL - /Job 在表单没有填充任何值时点击提交按钮

现在,我们通过浏览器来检查一下HTML表单中的Name控件,我们使用浏览器的开发工具来做这个工作

1f4be7df330686d9d8309d05965d1b5b.png

我们注意到它包含这个样式类- input-validation-error 代码如下:

<input class="form-control" type="text" data-val="true" data-val-required="The 姓名 field is required." id="Name" name="Name" value="">

没有通过验证时,我们将发现在所有控件上都添加了input-validation-error css,我们使用CSS样式在控件边框上添加红色,因此,在JobController的Index视图中添加样式代码块

@model JobApplication
@{
    ViewData["Title"] = "Job Application";
}
<style>
    .input-validation-error {
        border-color: red;
    }
</style>
<h2>Job Application</h2>
<form class="m-1 p-1" method="post">
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="Name" class="control-label"></label>
        </div>
        <div class="col-sm-11">
            <input asp-for="Name" class="form-control" />
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="DOB" class="control-label"></label>
        </div>
        <div class="col-sm-11">
            <input asp-for="DOB" type="text" asp-format="{0:d}" class="form-control" />
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="Sex" class="control-label"></label>
        </div>
        <div class="col-sm-1">
            <input asp-for="Sex" type="radio" value="M" class="form-check" />男
        </div>
        <div class="col-sm-1">
            <input asp-for="Sex" type="radio" value="F" class="form-check" />女
        </div>
        <div class="col-sm-9">
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="Experience" class="control-label"></label>
        </div>
        <div class="col-sm-11">
            <select asp-for="Experience" class="form-control">
                <option value="Select">选择</option>
                <option value="0">新手</option>
                <option value="1">0-1 年</option>
                <option value="2">1-2 年</option>
                <option value="3">2-3 年</option>
                <option value="4">3-4 年</option>
                <option value="5">4-5 年</option>
            </select>
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
        </div>
        <div class="col-sm-1">
            <input asp-for="TermsAccepted" class="form-label" />
        </div>
        <div class="col-sm-10">
            <label asp-for="TermsAccepted" class="form-check-label">
                我接受条款 & 条件
            </label>
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-11 offset-sm-1">
            <button type="submit" class="btn btn-primary">提交</button>
        </div>
    </div>
</form>

我们测试一下,当验证发生错误时控制器将显示红色边框,如下图所示:

5ee3261f26156dd99153a4d024f6d8a9.png

4 使用asp-validation-summary显示错误

我们用asp-validation-summary标签用显示ModelState中的错误信息,我们在Razor 视图中添加这个html的tag helper 并且显示所有的验证错误,在div标签内添加asp-validation-summary标签

@model JobApplication
@{
    ViewData["Title"] = "Job Application";
}
<style>
    .input-validation-error {
        border-color: red;
    }
</style>
<h2>Job Application</h2>
<div asp-validation-summary="All" class="text-danger"></div>
<form class="m-1 p-1" method="post">
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="Name" class="control-label"></label>
        </div>
        <div class="col-sm-11">
            <input asp-for="Name" class="form-control" />
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="DOB" class="control-label"></label>
        </div>
        <div class="col-sm-11">
            <input asp-for="DOB" type="text" asp-format="{0:d}" class="form-control" />
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="Sex" class="control-label"></label>
        </div>
        <div class="col-sm-1">
            <input asp-for="Sex" type="radio" value="M" class="form-check" />男
        </div>
        <div class="col-sm-1">
            <input asp-for="Sex" type="radio" value="F" class="form-check" />女
        </div>
        <div class="col-sm-9">
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
            <label asp-for="Experience" class="control-label"></label>
        </div>
        <div class="col-sm-11">
            <select asp-for="Experience" class="form-control">
                <option value="Select">选择</option>
                <option value="0">新手</option>
                <option value="1">0-1 年</option>
                <option value="2">1-2 年</option>
                <option value="3">2-3 年</option>
                <option value="4">3-4 年</option>
                <option value="5">4-5 年</option>
            </select>
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-1">
        </div>
        <div class="col-sm-1">
            <input asp-for="TermsAccepted" class="form-label" />
        </div>
        <div class="col-sm-10">
            <label asp-for="TermsAccepted" class="form-check-label">
                我接受条款 & 条件
            </label>
        </div>
    </div>
    <div class="mb-3 row">
        <div class="col-sm-11 offset-sm-1">
            <button type="submit" class="btn btn-primary">提交</button>
        </div>
    </div>
</form>

asp-validation-summary帮助标签会创建一个div把错误信息显示在该元素内,text-danger是Bootstrap的样式会给文本添加红色

再次运行你的应用程序并且在控件中不要输入任何值,提交表单,我们将会看到错误消息列表,如下图所示

829d6b44abd67c407753634e9ed9e842.png

asp-validation-summary属性可以设置3个值,分别是

名称

描述

All

显示记录的所有验证消息

ModelOnly

显示Model层的错误消息,它不包括为单个属性记录的那些验证消息

None

不显示任何验证的消息

5 显示单个模型验证错误消息

很显然,如果我们把模型验证的错误消息显示在每个控件旁边对客户是非常有利的,我们可以使用asp-validation-for标签来完成

例如:给属性名字显示验证的错误消息,在新的span元素中添加这个标签:

<span asp-validation-for="Name"></span>

现在进入JobController的Index视图,在Name属性输入框下面添加一个span控件

我们给每个属性都添加一个span 控件,需要修改一下span 标签的属性name – asp-validation-for="property"

代码如下:

@model JobApplication
@{
    Layout = "_Layout";
    ViewData["Title"] = "Job Application";
}
<style>
    .input-validation-error {
        border-color: red;
    }
</style>
<h2>Job Application</h2>
<div asp-validation-summary="All" class="text-danger"></div>
<form class="m-1 p-1" method="post">
    <div class="form-group">
        <label asp-for="Name"></label>
        <input asp-for="Name" class="form-control" />
        <span asp-validation-for="Name" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="DOB"></label>
        <input asp-for="DOB" type="text" asp-format="{0:d}" class="form-control" />
        <span asp-validation-for="DOB" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Sex"></label>
        <div>
            <input asp-for="Sex" type="radio" value="M" />Male
            <input asp-for="Sex" type="radio" value="F" />Female
        </div>
        <span asp-validation-for="Sex" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Experience"></label>
        <select asp-for="Experience" class="form-control">
            <option value="Select">Select</option>
            <option value="0">Fresher</option>
            <option value="1">0-1 years</option>
            <option value="2">1-2 years</option>
            <option value="3">2-3 years</option>
            <option value="4">3-4 years</option>
            <option value="5">4-5 years</option>
        </select>
        <span asp-validation-for="Experience" class="text-danger"></span>
    </div>
    <div class="form-group">
        <input asp-for="TermsAccepted" />
        <label asp-for="TermsAccepted" class="form-check-label">
            I accept the terms & conditions
        </label>
        <span asp-validation-for="TermsAccepted" class="text-danger"></span>
    </div>
    <button type="submit" class="btn btn-primary">Submit Application</button>
</form>

再次运行应用程序,在没有输入任何值时提交表单,这次你将看到单个错误消息显示在每个控件的旁边,下面图片显示错误消息:

f85d3bfdb02ccfd1d18a33a88e2ba2cc.png

源代码地址

https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/Fundamentals/AspNetCore.ModelValidation/AspNetCore.ModelValidation

参考文献

https://www.yogihosting.com/aspnet-core-model-validation/#custom-model-validation

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值