精通ASP.NET MVC ——模型验证

文章内容较长,用于记录自己学习。模型验证(Model Vaildation)是确保应用程序所接受的数据适合于绑定到模型,并且在不合适时给用户提供有用的信息,以帮助他们修正问题的过程。

准备示例项目 

新建一个空的MVC项目,名叫ModelVaildation

Model文件夹中,新建一个Appointment.cs的文件,如下图所示:

    public class Appointment{public string ClientName { get; set; }[DataType(DataType.Date)]public DateTime Date { get; set; }public bool TermsAccepted { get; set; }}

创建一个Home控制器,代码如下图所示:

    public class HomeController : Controller{// GET: Homepublic ViewResult MakeBooking(){return View(new Appointment { Date = DateTime.Now});}[HttpPost]public ViewResult MakeBooking(Appointment appt){//在实际项目中,此处是在数据库中存储新的Appointment对象return View("Completed", appt);}}

创建布局页_Layout.cshtml,代码如下图所示:

<!DOCTYPE html><html>
<head><meta charset="utf-8"/><meta name="viewport" content="width=device-width" /><title>@ViewBag.Title</title><style type="text/css">.field-validation-error {color:#f00;}.validation-summary-errors {color:#f00; font-weight:bold;}.input-validation-error {border:2px solid #f00; background-color :#fee;}input[type="checkbox"].input-validation-error {outline:2px solid #f00;}</style>
</head>
<body><div>@RenderBody()</div>
</body>
</html>

创建一个视图启动文件_ViewStart.cshtml,以便布局页运用于视图,如下图所示:

@{ Layout = "~/Views/Shared/_Layout.cshtml";
}

创建MakeBooking.cshtml视图,代码如下图所示: 

@model ModelVaildation.Models.Appointment
<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>MakeBooking</title>
</head>
<body>
<h4>Book an Appointment</h4>@using (Html.BeginForm()) {<p>Your Name : @Html.EditorFor(m => m.ClientName)</p><p>Appointment Date: @Html.EditorFor(m => m.Date)</p><p>@Html.EditorFor(m => m.TermsAccepted)</p><input type="submit" value="Make Booking"/>}
</body>
</html>

创建Completed.cshtml文件,代码如如下图所示: 

<html>
<head><meta name="viewport" content="width=device-width" /><title>Completed</title>
</head>
<body>
<h4> Your Name is confirmed</h4><p> Your Name :<b>@Html.EditorFor(m => m.ClientName)</b></p><p> The data of your appointment is :<b>@Html.DisplayFor(m => m.Date)</b></p>
</body>
</html>

运行程序并导航到/Home/MakeBooking ,输入文本数据,如下图所示:

            

点击按钮,结果如下: 

             

现在,我们需要增加三个验证来确定用户提交的时候是可接受的数据: 

1、用户必须提供一个姓名。

2、用户必须提供一个未来的可用的日期(以mm/dd/yyyy格式)。

3、用户必须选中复选框以接受条款和条件。

 


明确的验证模型 

修改Home控制器代码如下图所示:

    public class HomeController : Controller{// GET: Homepublic ViewResult MakeBooking(){return View(new Appointment { Date = DateTime.Now});}[HttpPost]public ViewResult MakeBooking(Appointment appt){if (string.IsNullOrEmpty(appt.ClientName)){ModelState.AddModelError("ClientName", "Please enter yourname");}if (ModelState.IsValidField("Date")){ModelState.AddModelError("Date", "Please enter a date in the future");}if (!appt.TermsAccepted){ModelState.AddModelError("TermsAccepted","You must accepted terms");}if (ModelState.IsValid){return View("Completed", appt);}else{return View();}}}

通过使用ModelState.IsValidField属性,来检查模型绑定器是否能够对一个属性赋值。对于Data属性就是这么做的,以确保模型绑定器能够解析用户所递交的值。如果无法从请求中解析到一个值,执行额外检查或者报告其他错误消息是没有意义的(当无法从请求数据为Date属性解析到一个值时,该错误会在ModelState.IsVaild中体现出来)。

在MakeBooking.cshtml视图中用来生成input元素的模板视图辅助器,会检查视图模型的验证错误。

如果相关属性有错误报告,那么辅助器对相应的Input元素添加一个CSS的class标签属性,其值为input-validation-error.这就是为什么一开始需要在布局页中设置CSS样式的原因。

在不输入任何数据的情况下,提交表单,页面如下所示:

 

 


显示验证消息 

通过显示验证消息可以告诉用户提示的是什么问题,在MakeBooking.cshtml文件中,增加如下图代码:

@model ModelVaildation.Models.Appointment
<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>MakeBooking</title>
</head>
<body>
<h4>Book an Appointment</h4>@using (Html.BeginForm()) {@Html.ValidationSummary();<p>Your Name : @Html.EditorFor(m => m.ClientName)</p><p>Appointment Date: @Html.EditorFor(m => m.Date)</p><p>@Html.EditorFor(m => m.TermsAccepted) I accept the terms &conditions</p><input type="submit" value="Make Booking"/>}
</body>
</html>

Html.ValidationSummary() 辅助器给用户显示了验证错误的摘要,如果没有错误,则不会生成任何HTML代码。

这些错误被标识成div元素的一个列表,对该元素运用了validation-summary-errors类,如下图所示:

                

 

ValidationSummary还有一些重载版本,允许开发人员指定显示模型级错误。前面用的ModelState注册的错误都是属性级的错误。

有用的VaildationSummary辅助器重载方法
重载方法描述
Html.ValidationSummary()生成所有验证错误的摘要
Html.ValidationSummary(bool)如果bool参数为ture,那么只显示模型级别错误。如果为false,那么便显示所有错误。
Html.ValidationSummary(string)在所有验证错误摘要之前显示一条消息(包括在string参数中)
Html.ValidationSummary(bool,string)在验证错误前显示一条消息。如果bool参数为true,只显示模型级别的错误

当存在由于两个或者多个属性值之间的相互作用而引发的错误时,可以使用模型级错误。举个例子:假设姓名为“Joe”的客户不能形成星期一的预约,修改Home控制器的代码如下图所示:

        [HttpPost]public ViewResult MakeBooking(Appointment appt){if (string.IsNullOrEmpty(appt.ClientName)){ModelState.AddModelError("ClientName", "Please enter yourname");}if (ModelState.IsValidField("Date") && DateTime.Now > appt.Date){ModelState.AddModelError("Date", "Please enter a date in the future");}if (!appt.TermsAccepted){ModelState.AddModelError("TermsAccepted","You must accepted terms");}if (ModelState.IsValidField("ClientName") && ModelState.IsValidField("Date") && appt.ClientName == "Joe" && appt.Date.DayOfWeek == DayOfWeek.Monday){ModelState.AddModelError("", "Joe Cannot book appointments OnMondays");}if (ModelState.IsValid){return View("Completed", appt);}else{return View();}}

修改MakeBooking.cshtml中代码如下:

@Html.ValidationSummary(true);

运行情况如下: 

          

在查看Joe是否企图预约在星期一之前,用ModelState.IsValidField方法来确认,已经有了合法的ClientNameDate 值。这意味着,除非前面在属性上的检查已经成功,否则是不会生成模板级错误的。给ModelState.AddModelError方法的第一个参数传递一个空字符串“ ”,便可以注册一条模型级错误。 但是同样带来了另一个问题,用户无法看到单选框未勾选的属性级错误了。

 


显示属性级验证消息 

为了能看到属性级错误,修改MakeBooking.cshtml代码如下所示:

@model ModelVaildation.Models.Appointment
<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>MakeBooking</title>
</head>
<body>
<h4>Book an Appointment</h4>@using (Html.BeginForm()) {@Html.ValidationSummary(true);<p>@Html.ValidationMessageFor(m => m.ClientName)</p><p>Your Name : @Html.EditorFor(m => m.ClientName)</p>@Html.ValidationMessageFor(m => m.Date)<p>Appointment Date: @Html.EditorFor(m => m.Date)</p>@Html.ValidationMessageFor(m => m.TermsAccepted)<p>@Html.EditorFor(m => m.TermsAccepted) I accept the terms &conditions</p><input type="submit" value="Make Booking"/>}
</body>
</html>

运行结果如下图所示:

          

如果所运用的属性有验证错误,辅助器会插入HTML到响应中,并生成像这样的元素: 

 


用元数据指定验证规则 

MVC框架也支持用源数据来表达模型验证规则。使用元数据的优点是,整个应用程序中运用绑定过程的任何地方,都会强制执行验证规则,而不只存在于个别动作方法中。

修改Appointment.cs文件中的代码:

    public class Appointment{[Required]public string ClientName { get; set; }[DataType(DataType.Date)][Required(ErrorMessage ="Please enter a date")]public DateTime Date { get; set; }[Range(typeof(bool),"true","true",ErrorMessage ="You must accept the terms")]public bool TermsAccepted { get; set; }}

以上代码中,Required注解属性指明如果用户未递交一个属性的值,便是一个验证错误。Range注解属性指明可接受值的一个子集 。

内建的验证注解属性
属性示例描述
Compare[ Compare("Myother Property") ]两个属性必须有同样的值。当你要求一个用户对一个属性提供两次同样的值的时候,这个是有用的。例如:一个邮件地址或者一个口令
Range[ Range(10,20) ]一个数字值(或实现了IComparable 的任何属性类型),必须不超出指定的最小值和最大值。为了指定只要一端的边界,可以用一个MinValue或者MaxValue常数,如[ Range(int.MaxValue,50)]
RegularExpression[ RegularExprssion(" pattern") ]一个字符串值,必须匹配指定的正则表达式模式。注意,该模式必须匹配用户提供的所有值。而不只是其中一个子串。磨人的,它是大小写敏感的,但是你可以通过运用(?!)修饰符,是大小写不敏感——[RegularExpression("(?!)mypattern")]
Required[Required]必须是一个非空值。或一个不是只含空格的字符串。如果你希望空格作为可接受值,可以用 [ Required(AllowEmtptyString = true)]
StringLength[StringLength(10)]一个字符串值。必须不超过指定的最大长度。也可以指定一个最小长度,[StringLength (10, MinimumLength = 2)]

 创建自定义的属性验证注解属性

通过从ValidationAttribtue类进行派生,并实现自定义验证逻辑,也可以添加自己的注解属性。创建一个Infrastructure文件夹,并在其中创建一个名称为MustBeTrueAttribute.cs的类文件。如下图所示:

    public class MustBeTrueAttribute:ValidationAttribute{public override bool IsValid(object value){return value is bool && (bool)value;}}

使用方法如下图所示:

        [MustBeTrue(ErrorMessage ="You must accept the terms")]public bool TermsAccepted { get; set; }

通过内建的验证注解属性进行派生 

也可以通过内建的验证注解属性来派生新类,这为我们提供了扩展内建验证注释属性的能力。代码如下图所示:

    public class FutrueDateAttribute:RequiredAttribute{public override bool IsValid(object value){return base.IsValid(value) && ((DateTime)value) > DateTime.Now;}}

使用方法如下图所示: 

        [FutrueDate(ErrorMessage ="Please enter a date")]public DateTime Date { get; set; }

创建模型验证注解属性 

到目前为止,所创建的自定义验证注解属性都是运用于个别模型属性的,这意味着他们只能触发属性级别的验证错误。也可以自定义注解属性来验证整个模型,它们将引发模型级错误。代码如下图所示:

    public class NoJoeOnMondaysAttribute:ValidationAttribute{public NoJoeOnMondaysAttribute(){ErrorMessage = "Joe cannot book appointments on Mondays";}public override bool IsValid(object value){Appointment app = value as Appointment;if (app == null || string.IsNullOrEmpty(app.ClientName) || app.Date == null){//还没有正确类型的模型要验证,或者还没有所需要的ClientName 和 Date 属性的值return true;}else{return !(app.ClientName == "Joe" && app.Date.DayOfWeek == DayOfWeek.Monday);}}}

使用方式如下图所示:

    [NoJoeOnMondays]public class Appointment{[Required]public string ClientName { get; set; }[DataType(DataType.Date)][FutrueDate(ErrorMessage ="Please enter a date")]public DateTime Date { get; set; }[MustBeTrue(ErrorMessage ="You must accept the terms")]public bool TermsAccepted { get; set; }}

 使用客户端验证

到目前为止,所使用的验证技术都是服务端验证。这意味着,用户把他们的数据递交给服务器,服务器验证这些数据,并返回验证结果(要么数据处理成功,要么列出需要修正的错误)。

在Web应用程序中,用户会期望得到及时的反馈——对服务器不作任何递交。这称为客户端验证,而且,这些通常是用JavaScript实现的。用户输入的数据在被放送给服务器之前就进行验证,给用户提供即时反馈并修正的机会。

客户端验证是由Web.Config文件中的两个设置来控制的。为了确保验证生效,必须确保两个设置都必须为true如下图所示:

            

添加验证库JS文件到_Layout.cshtml,顺序是很重要的,必须先添加jQuery库然后是微软验证库文件。

一旦启用了客户端验证,并确保在布局中引用了JavaScript库,就可以执行客户端验证了。最简单的方式是运用前面服务端验证所使用的注解属性,如RequiredRange以及StringLength等。 修复Appointment模型类如下图所示:

    public class Appointment{[Required][StringLength(10,MinimumLength =3)]public string ClientName { get; set; }[DataType(DataType.Date)]public DateTime Date { get; set; }public bool TermsAccepted { get; set; }}

运行程序并导航到/Home/MakeBooking,并在name字段中输入字母X,便可以看到客户端验证的效果: 

                       

在浏览器中呈现的反馈是即时的,不需要形成对服务器的请求。事实上,执行验证的JavaScript代码会阻止递交表单,直到不再出现验证错误为止。 

当用户更改错误时,反馈是即时的。如果你返回到name属性,并不断输入,当输入了三个或者更长的字符时,验证错误便会消失。但是如果继续输入,直到达到十一个字符长度时,便能看到错误消息再次提示。

 

 

 

 

 

 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/548525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[wbia 2.2] 对检索结果进行评估

评估对检索系统的性能&#xff1a; 由于我们这里的检索结果&#xff0c;是主要根据PageRank的排名&#xff0c;以及Lucene对文本的分词和相关性计算的最后得分&#xff0c;进行权值调整后得到的排名结果。 这里对我们检索系统的进行性能评估&#xff0c;这里主要评估的是检索结…

错误175:具有固定名称MySql.Data.MySqlClient的ADO.NET提供程序未在计算机或者应用程序配置文件中注册或者无法加载

背景&#xff1a; EF连接MySQL时报错&#xff0c;截图如下图所示&#xff1a; 网上翻阅了很多资料&#xff0c;感觉有一篇文章说的比较靠谱&#xff1a;点击阅读。解决问题的大致过程如下&#xff1a; 在尝试使用MySQL&#xff0c;ADO.NET&#xff08;数据库优先&#xff09;和…

精通ASP.NET MVC ——URL和Ajax辅助器方法

Ajax(或者&#xff0c;如果你愿意&#xff0c;也可以称为AJAX)是 Asynchronous JavaScripts and XML(异步JavaScripts与XML)。其XML部分并不如它往常那样意义重大&#xff0c;但是异步部分却使AJax十分有用。这是后台请求服务器数据&#xff0c;而不必重载Web页面的一种模型。M…

精通ASP.NET MVC ——控制器可扩展性

MVC中引导动作方法执行过程的请求流程管道中&#xff0c;有两个重要的部件&#xff1a;控制器工厂(Controller Factory) 和 动作调用器&#xff08;Action Invoker&#xff09;。控制器工厂负责创建对请求进行服务的控制器实例&#xff0c;动作调用器负责查找并调用控制器类中的…

永中向香港博览会主办方演示云办公(转载)

4月16号“香港国际资讯博览会”主办方香港贸发局对永中云办公产品非常感兴趣&#xff0c;由永中员工演示&#xff0c;并拍摄了演示视频。转载于:https://blog.51cto.com/premium/837675

Backbone.js学习笔记

为什么80%的码农都做不了架构师&#xff1f;>>> http://documentcloud.github.com/backbone var todoItem new TodoItem(); todoItem.url /todo; todoItem.fetch(); todoItem.get(description)var TodoItem Backbone.Model.extend({urlRoot: /todos }); var tod…

ASP.NET MVC中使用Autofac实现简单依赖注入

本文参考资料&#xff1a; 1、https://www.cnblogs.com/RayWang/p/11128554.html。 2、https://www.cnblogs.com/eedc/p/6127181.html 3、https://www.cnblogs.com/ancupofcoffee/p/5007649.html#top 前言 关于IoC和DI(依赖注入)的概念网上一搜一大把。简单来说&#xff0c;Io…

初探EntityFramework——来自数据库的EF设计器

本文通过简单的示例&#xff0c;先初步了解下EF四种设计模式之一&#xff1a;来自数据库的EF设计器。 来自数据库的EF设计器&#xff0c;顾名思义&#xff0c;需要有新建的数据库和表结构&#xff0c;才能生成EF设计器&#xff0c; 在本地新建数据库KTStore&#xff0c;并且新建…

初探EntityFramework——空EF设计器模型

如果没有任何现存数据库架构&#xff0c;可以使用空的EF设计器模型。本文将通过简单示例&#xff0c;了解如何使用空EF设计器模型。 新建空的控制器应用程序EFDesignerDemo&#xff0c;如下图所示&#xff1a; 在项目中右键&#xff0c;选择“添加”&#xff0c;然后是“新建项…

初探EntityFramework——来自数据库的Code First

Entity Framkwork从第二版&#xff08;EF4&#xff09;开始&#xff0c;支持新的CodeFirst模式&#xff08;程序代码优先&#xff09;&#xff0c;以自定义类定义数据模型。简化了EF的开发过程。本文章使用简单的示例来说明如何使用来自数据库的CodeFirst模式。 新建一个空的控…

初探EntityFramework——空Code First模型

如果不是从现有的系统升级&#xff0c;想要创建全新的项目可以从“空Code First模型开始”。“空CodeFirst模型”要先创建类&#xff0c;Visual Studio会从项目第一次执行的时候根据连接自动创建需要的数据库结构。本文将简单示例说明如何使用“空CodeFirst模型”。 新建控制台…

初探EntityFramework——实体类结构映射

实体类与数据表的映射有一套专用的规则。Code First 采用的惯例优于预先设置的设计&#xff0c;在没有任何设置的情况下&#xff0c;自动检测模型结构并推导出默认设置以简化类的设计&#xff0c;因此不需要特别设置类的属性即可完成模型设计。 例如&#xff0c;当DbContext的模…

深入了解EntityFramework——数据注解属性

当惯例规则不符合设计需求时&#xff0c;我们可以使用数据注解配置打造更合适的数据库模型。本文根据示例项目对常用的数据注解属性做一个简要的举例说明。 EFCodeFirst使用的约定大于配置的的编程模式&#xff0c; 这种模式利用默认约定根据我们的领域模型建立概念模型。然我们…

Android上实现柱状图表

Android上实现柱状图算法实现 第一步&#xff1a; 获取Android设备的屏幕大小 第二步&#xff1a; 在View对象中使用Canvas绘制蓝色边框与白色背景XY轴两条线&#xff0c;代码如下 第三步&#xff1a; 绘制柱状图标题 第四步&#xff1a; 根据数据集计算出每个系列数据所占X轴的…

深入了解EntityFramework——Fluent API

Fluent API 除了惯例原则与属性数据注解外&#xff0c;FluentAPI是另一种支持实体类配置设置的方式。与属性数据注解相比&#xff0c;它提供了更广泛的功能与设置弹性。实体类若同时设置了数据注解&#xff0c;则采用的优先权是“Fluent API” > "数据注解" &g…

深入了解EntityFramework——Lazy Loading与Eager Loading

Lazy Loading&#xff1a;延迟加载。Eager Loading&#xff1a;贪婪加载。 首先通过一个简单的控制台应用程序例子说明延迟加载&#xff1a; 订单主表和订单从表&#xff0c;并且订单主表和订单从表是一对多的关系&#xff0c;代码如下图所示&#xff1a; //订单主表public cl…

SQL – 2.SQLServer的管理 + 3.SQL基础1 + 4.SQL基础2

SQLServer的管理 常用字段类型&#xff1a;bit(可选值0、1)、datetime、int、varchar、nvarchar&#xff08;可能含有中文用nvarchar&#xff09;varchar、nvarchar 和char(n)的区别&#xff1a; char(n)不足长度n的部分用空格填充。Var&#xff1a;Variable&#xff0c;可变的…

EntityFramework进阶——继承

通过类型继承&#xff0c;我们可以更弹性地处理数据&#xff0c;有3中相关的技巧&#xff0c;即TPH&#xff0c;TPT&#xff0c;TPC。 Table Per Hierarchy&#xff08;TPH&#xff09; 当单个数据表存储不同数据类型时&#xff0c;在数据模型的设计上&#xff0c;可以使用Tab…

EntityFramework进阶——数据编辑与维护

实体数据对象状态 在EF环境下&#xff0c;应用程序更改数据对象会引发数据集状态的变更&#xff0c;可能的状态有以下几种&#xff1a; 数据对象状态列表Added添加实体对象创建到实体集中&#xff0c;数据未添加进数据库Modified实体对象已经存在于实体数据集中&#xff0c;数…

第六章扩展——VMA

由 user process角度来说明的话&#xff0c;VMA 是 user process 里一段 virtual address space 区域&#xff1b;virtual address space 是连续的内存空间&#xff0c;当然VMA 也会是连续的空间。VMA 对 Linux 的主要好处是&#xff0c;可以内存的使用更有效率&#xff0c;並且…