博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
asp.net core系列 45 Web应用 模型绑定和验证
阅读量:5863 次
发布时间:2019-06-19

本文共 9044 字,大约阅读时间需要 30 分钟。

一. 模型绑定

  ASP.NET Core MVC 中的模型绑定,是将 HTTP 请求中的数据映射到action方法参数。 这些参数可能是简单类型的参数,如字符串、整数或浮点数,也可能是复杂类型的参数。 当 MVC 收到 HTTP 请求时,它会将此请求路由定位到控制器的指定action方法。默认路由模板为 {controller=Home}/{action=Index}/{id?}

//例如:请求URL     http://contoso.com/movies/edit/2         //映射到movies/edit/2    public IActionResult Edit(int? id)

   上面Url请求对应movies控制器下的Edit方法,该方法接受名为 id 的可选参数。MVC会将Edit中的id参数绑定到路由值中具有相同名称的值。 URL 路由中的字符串不区分大小写。

  上面示例绑定的参数是简单类型,如果参数是一个类,例如Movie类型,该类包含简单和复杂类型作为属性,MVC的模型绑定仍然可以很好地处理它。它使用反射和递归来遍历寻找匹配的复杂类型的属性(如:Collection、Dictionary)。

  如果模型绑定失败,MVC 不会引发错误,参数值会是null。 如果HTTP 请求中的数据是用户输入的值,在action中应使用 ModelState.IsValid 属性检查,不需要手动去检查。

  注意:若要实现模型绑定,该类必须具有要绑定的公共默认构造函数和公共可写属性。 发生模型绑定时,在使用公共默认构造函数对类进行实例化后才可设置属性。

  模型绑定完成后,将发生模型验证。 对于绝大多数开发方案,默认模型绑定效果极佳。还可以扩展,如果有特殊需求,则可自定义内置行为包括:模型绑定特性、全局自定义模型绑定和验证、绑定请求正文中的带格式数据(JSON、XML 和许多其他格式)、还有高级篇中自定义模型绑定。这里不在说明,请查看文档。

 

二.模型验证

  在将数据存储到数据库之前,应用程序必须先验证数据。在 MVC 中,验证发生在客户端和服务器上。

  

  2.1 验证属性

    验证属性是模型验证的一种方法, 概念上类似于对数据库表中字段的验证, 验证属性在属性级别指定,下面是一个示例:

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; }}

   常用的内置验证属性包括:[CreditCard] 信用卡格式、 [Compare]匹配两个属性、[EmailAddress] 邮件格式、[Phone] 电话格式、[Range] 给定范围内、[RegularExpression] 正则表达式、[Required]必须属性值、[StringLength] 最大长度、[Url] URL格式,还可以包括自定义验证属性(例如ClassicMovie)。所有的内置验证属性

   

   2.2 自定义验证

     上面的验证属性适用于大多数验证需求。 但是,某些验证规则特定于你的业务。在 MVC 中创建自定义验证属性很简单。只需从 ValidationAttribute 继承并重写 IsValid方法。 IsValid 方法采用两个参数,第一个是名为 value 的对象,第二个是名为 validationContext 的 ValidationContext 对象。 Value 引用自定义验证程序要验证的字段中的实际值。

///     /// 自定义验证    ///     public class ClassicMovieAttribute : ValidationAttribute    {        private int _year;        ///         /// 验证规则值        ///         ///         public ClassicMovieAttribute(int year)        {            _year = year;        }        protected override ValidationResult IsValid(object value, ValidationContext validationContext)        {            Movie movie = (Movie)validationContext.ObjectInstance;            //用户不能将 1960 年以后发行的电影的流派设置为 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}.";        }    }

     运行程序,ReleaseDate是1989年,Genre是Classic,点击Save,验证是在服务端进行,显示错误消息,没有经过前端js验证,如下所示:

  

         2.3 客户端js验证介绍

    jQuery 非介入式验证脚本是一个自定义微软前端库,建立在流行的 jQuery Validate 插件。客户端验证原理是: MVC 的标记帮助程序和 HTML 帮助程序则能够使用模型属性中的验证特性和类型元数据,呈现需要验证的表单元素中的 HTML 5 data- 属性。MVC 为内置模型属性和自定义模型属性生成 data- 属性。然后,jQuery 非介入式验证分析 data- 属性并将逻辑传递给 jQuery Validate,从而将服务器端验证逻辑有效地“复制”到客户端。 可以使用相关标记帮助程序在客户端上显示验证错误。

    下面示例表单中,asp- 标记帮助程序代码如下:

    标记帮助程序将生成以下source html。请注意,HTML 输出中的 data-属性与 ReleaseDate 属性的验证特性相对应。下面的 data-val-required 属性包含在用户未填写发行日期字段时将显示的错误消息。jQuery 非介入式验证将此值传递给 jQuery Validate required() 方法,该方法随后在随附的 <span> 元素中显示该错误消息。

Movie

   

  2.4 动态表单添加验证

    在创建动态表单后,需要立即对其进行分析。 例如,下面的代码展示如何对通过 AJAX 添加的表单设置客户端验证。

$.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);        //验证第一个表单        var forms = container.getElementsByTagName("form");        var newForm = forms[forms.length - 1];        //分析表单的 data- 属性        $.validator.unobtrusive.parse(newForm);    }})

     $.validator.unobtrusive.parse() 方法分析该选择器内表单的 data- 属性。当用户填写表单中的属性值提交时, 这些属性的值传递到 jQuery Validate 插件中,以便表单展示所需的客户端验证规则。

    下面用一个简单示例来说明:

    (1)  创建dynamic-form-validate.js文件,模拟动态生成表单,以及点击(#idbtn)按钮时验证:

var newFormHTML = "
";newFormHTML += "
";newFormHTML += "
";newFormHTML += "
";newFormHTML += "
";newFormHTML += "
";newFormHTML += "
";newFormHTML += "
";newFormHTML += "
";newFormHTML += "
";$("#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";}

Create

@section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} }

     运行程序,点击"动态加载表单" 调用js将html表单添加到form-container元素容器中,点击save提示该字段不能为空,效果如下所示:

  

  2.5 动态控件添加验证

    当向表单动态添加控件(比如: <input/> 和 <select/>)时,需要更新表单上的验证规则。做法是应当先删除现有的验证数据,然后重新分析整个表单,如下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) {         //向表单动态添加Input控件        var form = document.getElementById("my-form");        form.insertAdjacentHTML("beforeend", newInputHTML);         //移除现有的验证        $(form).removeData("validator")    // Added by jQuery Validate               .removeData("unobtrusiveValidation");   // Added by jQuery Unobtrusive Validation          //重新分析整个表单        $.validator.unobtrusive.parse(form);    }})

 

  2.6  IClientModelValidator

    在上面2.2自定义验证中,继承了ValidationAttribute进行服务端验证,还可以结合实现IClientModelValidator接口实现客户端验证,该接口用来控制要添加哪些 data- 属性。实现接口如下所示:

///     /// 自定义验证    ///     public class ClassicMovieAttribute : ValidationAttribute,IClientModelValidator    {        private int _year;        ///         /// 年份参考值        ///         ///         public ClassicMovieAttribute(int year)        {            _year = year;        }        protected override ValidationResult IsValid(object value, ValidationContext validationContext)        {            Movie movie = (Movie)validationContext.ObjectInstance;            //用户不能将 1960 年以后发行的电影的流派设置为 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
attributes, string key, string value) { if (attributes.ContainsKey(key)) { return false; } attributes.Add(key, value); return true; } }

     生成的源html代码如下所示:

     在上面虽然实现了IClientModelValidator接口,但jQuery不了解规则或消息,还需要自定义classicmovie客户端验证方法,添加到jQuery validator对象。脚本如下所示:

//添加验证方法$.validator.addMethod('classicmovie',function (value, element, params) {         //value ,是当前验证的元素的值。         //element  元素本身。         //params 是传入的参数(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;    });//注册一个适配器,参数1是适配器名称,参数2是验证规则的名称$.validator.unobtrusive.adapters.add('classicmovie',['year'],function (options) {        //适配器规则绑定到jquery validation上面        options.rules['classicmovie'] = [parseInt(options.params['year'])];        options.messages['classicmovie'] = options.message;    });

     运行程序,ReleaseDate是1989年,Genre是Classic,点击Save,客户端验证返回false,提示错误信息,如下所示:

    

  参考文献

    

    

  

转载于:https://www.cnblogs.com/MrHSR/p/10563157.html

你可能感兴趣的文章
C# & .NET 1.0-4.0
查看>>
逻辑读时的cbc latch(一)
查看>>
互联网金融的创新之门在哪里?
查看>>
如何新增、修改、删除用户,及如何授权
查看>>
我的友情链接
查看>>
【一壶浊酒在51CTO】
查看>>
VMware虚拟化技术培训(9) 桌面虚拟化之一
查看>>
How To Safely Delete Windows.old Folder In Windows 7
查看>>
初始化列表的用法说明
查看>>
绝对路径和相对路径
查看>>
servlet和jsp请求转发和重定向
查看>>
sed命令的用法
查看>>
ESXI 补丁升级回退
查看>>
ConcurrentHashMap putIfAbsent和的put区别
查看>>
文件共享与用户认证分离系统的搭建
查看>>
VC++线程同步(二) Mutex互斥量的例子
查看>>
Java工具类——UUIDUtils
查看>>
CentOS 7 部署LVS集群(DR模式、NAT模式,LVS+keepalived)
查看>>
程序清单4.9_flags.c程序_《C Primer Plus》P72
查看>>
总结——性能面试题
查看>>