ASP.NET MVC - 模型验证/表单验证

创建时间:
2014-01-07 01:34
最近更新:
2018-09-21 09:44

Resource - Official

  1. jquery.validate.js 的官网
  2. ASP.NET Core MVC 中的模型验证 - 自定义验证、客户端验证、远程验证 等

ASP.NET MVC 模型验证 的 配置

一、Web.config 文件中必须有以下配置:

<appSettings>
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>

二、页面必须引用以下脚本:

  • jquery.js
  • jquery.validate.js
  • jquery.validate.unobtrusive.js

RequiredAttribute 的使用说明

"不可以为 null 的值类型" (如 decimal、int、float、DateTime) 本质上是必须的,不需要 RequiredAttribute,应用 不 对 "被标记了 RequiredAttribute 的 不可以为 null 的类型" 执行 服务器端验证 检查。-- 摘自 ASP.NET Core MVC 中的模型验证

Validation Attribute (验证特性) 测试 - TestAllValidateAttribute.cs

//ErrorMessage 中可使用占位符,{0} 表示 字段名 或 DisplayAttribute.Name,{1} 表示该 Attribute 的第一个参数,{2} 表示该 Attribute 的第二个参数。

//会执行验证的Attribute:
//Compare
//Required
//Range
//Remote
//RegularExpression
//StringLength
//和字段显示相关、不执行验证的Attribute:
//DataType - 2015-10-29 发现该枚举中居然没有 number
//Display
//DisplayFormat
//HiddenInput
//ReadOnly
//ScaffoldColumn
//其它:
//AllowHtml
//Key
//UiHint

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace Cms.Models
{
    [DisplayName("Category Edit")] //在另一命名空间中,通常不用它、而是用下一行:
    [Display(Name = "类别名称")]
    public class TestAllAttribute
    {
        [UiHint]//尚未研究。
        [Key]
        [ReadOnly(true)]//尚未发现其用途。测试发现并不会在 <input type="text" /> 中生成 readonly 属性。
        [ScaffoldColumn(false)]//ScaffoldColumnAttribute仅1种构造函数,其参数bool scaffold指定类或数据列是否使用基架。如此参数设置为false,则该字段不会在View中显示,为该字段定义的任何验证自然都不会生效。
        [DisplayFormat(ApplyFormatInEditMode = true, ConvertEmptyStringToNull = true, DataFormatString = "{0:c}", HtmlEncode = true, NullDisplayText = "无")]//指定数据显示的样式。不属于验证特性。ApplyFormatInEditMode参数指示数据字段处于编辑模式时,是否将DataFormatString参数指定的格式设置字符串应用于字段值。
        [DisplayFormat(DataFormatString = "yyyy-MM-dd")] // 直接输出 "yyyy-MM-dd"。
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}")]
        [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode=true)] // Display date data field in the short format 11/12/08. Also, apply format in edit mode.
        [DisplayFormat(DataFormatString = "{0:C}")] // Display currency data field in the format $1,345.50.
        [HiddenInput(DisplayValue = false)] //将该字段输出为[type=hidden]。详见本站专文。
        public int Id { get; set; }

        [AllowHtml]//请求时,允许此字段包含HTML标记
        [Display(Name = "类别名称")]//将显示此处设置的Name,而非字段名。
        [Display(Name = "类别名称", AutoGenerateField = true)]//AutoGenerateField作用不详,暂不使用。
        [Required(ErrorMessage = "Please enter {0}.")]//因jquery.validate.js中为required预设错误信息时无法使用占位符,故Tony统一使用此行代码。
        [Required]//Tony测试记录:默认的ErrorMessage为"{0} 字段是必需的。"。
        [Required(AllowEmptyStrings = false, ErrorMessage = "请填写标题")]
        [StringLength(T.P.Article._SizeOfTitle)]//Tony测试记录:默认的ErrorMessage为"字段 {0} 必须是最大长度为 {1} 的字符串。"。
        [StringLength(T.P.Article._SizeOfTitle, ErrorMessage = "{0} 不能超过 {1} 个字符。")]
        [StringLength(int.MaxValue, ErrorMessage = "{0} 不能少于 {2} 个字符。", MinimumLength = T.Account.Cmn._MinPwLengthOfUser)]//Tony测试记录:当maximumLength参数的值为int.MaxValue时,生成的HTML中没有data-val-length-max属性。
        [DataType(DataType.EmailAddress)]//决定着输出何种HTML表单控件,如:[type=password]、[type=email]、textarea等等。
        //Tony 测试记录: 设置 DataType.EmailAddress 之后无需 RegularExpressionAttribute,MVC就会自动验证 [type=email],此时使用 jquery.validate.js 中预设的错误信息,且 DataTypeAttribute 的ErrorMessage 不起作用。注意,MVC 自动验证 [type=email] 时,如果在正确的 EmailAddress 前或后有空格,在 CM29 中可通过验证、在 IE9 中无法通过验证,行为不一致且IE用户体验不佳,因此 Tony 总是使用[RegularExpression(" *" + T.Re._Email + " *", ErrorMessage = "Please enter a valid {0}.")]
        [DataType(DataType.MultilineText)]
        [DataType(DataType.MultilineText, ErrorMessage = "何时使用此字段值?")]
        [Remote("ValidateNameUnique", "RoleOfStaff", "Account", AdditionalFields = "RoleOfStaffId")]//使用$.ajax()调用服务器端验证。
        [Remote("ValidateNameUnique", "RoleOfStaff", "Account", AdditionalFields = "RoleOfStaffId", ErrorMessage = "Existing Staff Role with same name.", HttpMethod = "post")]
        public int Name { get; set; }

        //比较两个表单控件的值是否相同。
        [System.ComponentModel.DataAnnotations.Compare(
            "Password", ErrorMessage = "The password and confirmation password do not match.")]
        [System.Web.Mvc.Compare(
            "Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }

        //Tony 测试发现 RegularExpressionAttribute 的 pattern 实参不能拼接字符串,否则编译时将报错。
        [RegularExpression(" *" + T.Re._Email + " *", ErrorMessage = "Please enter a valid {0}.")]
        //Tony 测试发现以下两行行为相同,这表明 ^ 与 $ 不是必须的:
        [RegularExpression(@"^\d+$", ErrorMessage = "Please enter only digits.")]
        [RegularExpression(@"\d+", ErrorMessage = "Please enter only digits.")]
        public string Email { get; set; }

        [Range(18, 60, ErrorMessage = "{0} 必须在 {1} 和 {2} 之间。")]//验证范围。
        [Range(typeof(decimal), "0.03", "0.15", ErrorMessage = "{0} 必须在 {1} 和 {2} 之间。")]
        public int Age { get; set; }
    }
}

System.ComponentModel 命名空间

  • System.ComponentModel 命名空间 - The System.ComponentModel namespace provides classes that are used to implement the run-time and design-time behavior of components and controls. This namespace includes the base classes and interfaces for implementing attributes and type converters, binding to data sources, and licensing components.此命名空间提供用于实现组件和控件的运行时和设计时行为的类。此命名空间包括用于特性和类型转换器的实现、数据源绑定和组件授权的基类和接口。
  • System.ComponentModel.DisplayNameAttribute 类

Note: 因为 该命名空间中 仅发现上述一个 可用于 表单验证的特性类,其它表单验证特性均不在该命名空间中。而 System.ComponentModel.DataAnnotations.DisplayAttribute 类 与上述特性类 作用相同,更合理、更一致,因此统一不使用 该命名空间 与 该特性类。

System.ComponentModel.TypeDescriptor 类

System.ComponentModel.TypeDescriptor 类
提供有关组件特征的信息,如组件的特性、属性和事件。此类不能被继承。
.NET Framework 提供了两种访问某类型的元数据的方式:通过 System.Reflection 命名空间中提供的反射 API,以及通过 TypeDescriptor 类。
反射是可用于所有类型的通用机制,因为它是基于根 Object 类的 GetType 方法建立的。反射为某个类型返回的信息不可扩展,因为编译了目标类型后就不能对其进行修改。
相反,TypeDescriptor 是组件的可扩展检查机制:即实现 IComponent 接口的那些类。与反射不同,它不会检查方法。可通过目标组件的 Site 可用的一些服务来动态扩展 TypeDescriptor。

Resource

  1. DataAnnotation TypeDescriptor - 脱离 MVC 独立验证
  2. 使用 TypeDescriptor 给类动态添加 Attribute

System.ComponentModel.DataAnnotations 命名空间

System.ComponentModel.DataAnnotations 命名空间
该命名空间提供定义 ASP.NET MVC 和 ASP.NET 数据控件的类的特性。
该命名空间下有 30 个 XxxAttribute 类 (.NET Framework 4.6 and 4.5 中)。

System.ComponentModel.DataAnnotations.dll

命名空间、程序集:System.ComponentModel.DataAnnotations
在                System.ComponentModel.DataAnnotations.dll 中

System.ComponentModel.DataAnnotations.DisplayFormatAttribute 类

DisplayFormatAttribute 类

Specifies how data fields are displayed and formatted by ASP.NET Dynamic Data.

[AttributeUsageAttribute(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class DisplayFormatAttribute : Attribute

以下为该类的全部属性 (6 个):

ApplyFormatInEditMode 属性

Gets or sets a value that indicates whether the formatting string that is specified by the DataFormatString property is applied to the field value when the data field is in edit mode.
true if the formatting string applies to the field value in edit mode; otherwise, false. The default is false.
By default, the formatting string that is specified by the DataFormatString property is applied to field values only when the data-bound control is in read-only mode.

//Display date data field in the short format 11/12/08.
//Also, apply format in edit mode.
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]
public object SellStartDate;

ConvertEmptyStringToNull 属性

Gets or sets a value that indicates whether empty string values ("") are automatically converted to null when the data field is updated in the data source.
true if empty string values are automatically converted to null; otherwise, false. The default is true.
Users might enter an empty string for a field value. Use the ConvertEmptyStringToNull property to specify whether an empty string value is automatically converted to null when the data field is updated in the database.

// Display the text [Null] when the data field is empty.
// Also, convert empty string to null for storing.
[DisplayFormat(ConvertEmptyStringToNull = true, NullDisplayText = "[Null]")]
public object Size;

2018-05-07 Tony 测试记录

提交表单时,空文本框 在 POST 中值为 ""。但是默认情况下 ASP.NET MVC 的模型绑定,会将该值 自动转换 为 null。在 视图模型 的 对应属性上 使用 [DisplayFormat(ConvertEmptyStringToNull = false)] 可禁止该 自动转换。

DataFormatString 属性

Gets or sets the display format for the field value.
A formatting string that specifies the display format for the value of the data field. The default is an empty string (""), which indicates that no special formatting is applied to the field value.

// Display currency data field in the format $1,345.50.
[DisplayFormat(DataFormatString = "{0:C}")]
public object StandardCost;
// Display date data field in the short format 11/12/08.
// Also, apply format in edit mode.
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]
public object SellStartDate;

HtmlEncode 属性

Gets or sets a value that indicates whether the field should be HTML-encoded.

NullDisplayText 属性

Gets or sets the text that is displayed for a field when the field's value is null.
The default is an empty string (""), which indicates that this property is not set.
Sometimes a data field's value is stored as null values in the source.
You can specify custom text to display for data fields that have a null value by setting the NullDisplayText property.
If this property is not set, null field values are displayed as empty strings ("").
To convert an empty string field value to a null value, you must set the ConvertEmptyStringToNull property to true.
By default, a DynamicField object displays null values as empty strings. To display a different value, set the NullDisplayText property.

// Display the text [Null] when the data field is empty.
// Also, convert empty string to null for storing.
[DisplayFormat(ConvertEmptyStringToNull = true, NullDisplayText = "[Null]")]
public object Size;

System.Attribute.TypeId 属性

When implemented in a derived class, gets a unique identifier for this Attribute.
An Object that is a unique identifier for the attribute.
As implemented, this identifier is merely the Type of the attribute. However, it is intended that the unique identifier be used to identify two attributes of the same type.

System.ComponentModel.DataAnnotations.ValidationAttribute 类

System.ComponentModel.DataAnnotations.ValidationAttribute 类 - Serves as the base class for all validation attributes. 用作所有验证特性的基类。This class enforces validation, based on the metadata that is associated with the data table. 此类强制执行基于与数据表相关联的元数据的验证。You can override this class to create custom validation attributes. 你可以重写此类,以创建自定义验证特性。网摘: 所有的 验证特性 都直接或者间接 继承自 此类型。

Inheritance Hierarchy

System.Object
  System.Attribute
    System.ComponentModel.DataAnnotations.ValidationAttribute
      System.ComponentModel.DataAnnotations.CompareAttribute
      System.ComponentModel.DataAnnotations.CustomValidationAttribute
      System.ComponentModel.DataAnnotations.DataTypeAttribute
      System.ComponentModel.DataAnnotations.MaxLengthAttribute
      System.ComponentModel.DataAnnotations.MinLengthAttribute
      System.ComponentModel.DataAnnotations.RangeAttribute
      System.ComponentModel.DataAnnotations.RegularExpressionAttribute
      System.ComponentModel.DataAnnotations.RequiredAttribute
      System.ComponentModel.DataAnnotations.StringLengthAttribute
      System.Web.Security.MembershipPasswordAttribute

System.ComponentModel.DataAnnotations.DataTypeAttribute 类

System.ComponentModel.DataAnnotations.DataTypeAttribute 类
指定要与数据字段关联的附加类型的名称。
DataTypeAttribute 特性允许使用比数据库内部类型更加具体的类型来标记字段。类型名称选自 DataType 枚举类型。例如,可以将包含电子邮件地址的字符串数据字段指定为 EmailAddress 类型。字段模板随后将访问此信息,以修改数据字段的处理方式。

Inheritance Hierarchy

System.Object
  System.Attribute
    System.ComponentModel.DataAnnotations.ValidationAttribute
      System.ComponentModel.DataAnnotations.DataTypeAttribute
        System.ComponentModel.DataAnnotations.CreditCardAttribute
        System.ComponentModel.DataAnnotations.EmailAddressAttribute
        System.ComponentModel.DataAnnotations.EnumDataTypeAttribute
        System.ComponentModel.DataAnnotations.FileExtensionsAttribute
        System.ComponentModel.DataAnnotations.PhoneAttribute
        System.ComponentModel.DataAnnotations.UrlAttribute

System.Web.Mvc.DataAnnotationsModelValidator<TAttribute> 类

System.Web.Mvc.DataAnnotationsModelValidator<TAttribute> 类
为指定的验证类型提供模型验证程序

Inheritance Hierarchy

System.Object
  System.Web.Mvc.ModelValidator
    System.Web.Mvc.DataAnnotationsModelValidator
      System.Web.Mvc.DataAnnotationsModelValidator<TAttribute>
        System.Web.Mvc.MaxLengthAttributeAdapter
        System.Web.Mvc.MinLengthAttributeAdapter
        System.Web.Mvc.RangeAttributeAdapter
        System.Web.Mvc.RegularExpressionAttributeAdapter
        System.Web.Mvc.RequiredAttributeAdapter
        System.Web.Mvc.StringLengthAttributeAdapter

《ASP.NET MVC 3 高级编程》中与表单验证相关的章节

  • Page 115 - 数据注解和验证
  • Page 188 - 客户端验证
  • Page 312 - 验证模型

本地化、全球化、多语言、资源文件

//From 《ASP.NET MVC 3 高级编程》 Page 121:
[Required    (     ErrorMessageResourceType=typeof(ErrorMessages), ErrorMessageResourceName="LastNameRequired")]
[StringLength(160, ErrorMessageResourceType=typeof(ErrorMessages), ErrorMessageResourceName="LastNameTooLong")]
public string LastName { get; set; }

Validation Attribute (验证特性) 的共性

  • 每个验证特性都允许传递一个带有自定义错误提示消息的参数 "ErrorMessage"。
  • 自定义的错误提示消息在字符串中有一个格式项。内置特性使用友好的属性显示名称格式化错误提示消息字符串,例如 [Required(ErrorMessage="Your {0} is required.")]

定义在命名空间 System.ComponentModel.DataAnnotations 中的 "数据注解特性"

[Required]
[StringLength(160, MinimumLength=3)]
public string FirstName { get; set; }

[RegularExpression(@"[A-Za-z0-9]+\.com")]
public string Email { get; set; }

[Range(35, 44)]
public int Age { get; set; }

[Range(typeof(decimal), "0.00", "49.99")]
public int Price { get; set; }

定义在命名空间 System.Web.Mvc 中的 "数据注解特性"

//in model:
[Remote("CheckUserName", "Account")]
public string UserName { get; set; }
//in action:
public JsonResult CheckUserName(string username)
{
	var result = Membership.FindUsersByName(username).Count == 0;
	return Json(result, JsonRequestBehavior.AllowGet);
}

[Compare("Email")]
public string EmailConfirm { get; set; }

System.ComponentModel.DataAnnotations.DisplayAttribute 不能用于 class

原因详见本文下一节的源码。

Model

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

[DisplayName("xxx")]
//[Display(Name = "yyy")] //编译时报错: "特性“Display”对此声明类型无效。它只对“method, property, indexer, field, param”声明有效。"
public class BookListFilter
{
    [Display(Name = "Classification")]
    public string BookClassificationCode { get; set; }
}

View

@Html.LabelForModel()
@Html.LabelForModel("yyy", new { style = "color:red" })

Output

<label for="">xxx</label>
<label for="" style="color:red">yyy</label>

Source Code of System.ComponentModel.DataAnnotations.DisplayAttribute from JetBrains dotPeek 1.0 at 2015-11-04

Excerpt:

// Type: System.ComponentModel.DataAnnotations.DisplayAttribute
// Assembly: System.ComponentModel.DataAnnotations, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.ComponentModel.DataAnnotations.dll
namespace System.ComponentModel.DataAnnotations
{
  [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
  [__DynamicallyInvokable]
  public sealed class DisplayAttribute : Attribute { }
}

Validation Attribute (验证特性) 的原理

ASP.NET MVC 的验证特性是由
模型绑定器、
模型元数据、
模型验证器、
模型状态
组成的协调系统的一部分。

-- 《ASP.NET MVC 3 高级编程》Page 122

执行验证 ("在模型绑定时隐式执行" 或 "调用 TryUpdateModel() 显式执行")

摘自:《ASP.NET MVC 3 高级编程》Page 122。

默认情况下,ASP.NET MVC 框架在模型绑定时执行验证逻辑。

在操作方法带有参数时,模型绑定将隐式地执行:

[HttpPost]
public ActionResult Create(Album album)
{
	// the album parameter was created via model binding
}

// or:

[HttpPost]
public ActionResult AddressAndPayment(Order newOrder)
{
	// the "newOrder" parameter was created via model binding.

	if(ModelState.IsValid){
		newOrder.Username = User.Identity.Name;
		newOrder.OrderDate = DateTime.Now;
		storeDB.Orders.Add(newOrder);
		storeDB.SaveChanges();

		// process the order:
		var cart = ShoppingCart.GetCart(this);
		cart.CreateOrder(newOrder);
		return RedirectToAction("Complete", new { id = newOrder.OrderId });
	}
	// invalid - redisplay with errors:
	return View(newOrder);
}

也可以利用控制器的 UpdateModel 或 TryUpdateModel 方法显式地执行模型绑定:

[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
	var album = storeDB.Albums.Find(id);
	if(TryUpdateModel(album)){
		// ...
	}
}

// or:

[HttpPost]
public ActionResult AddressAndPayment(FormCollection collection)
{
	var newOrder = new Order();
	TryUpdateModel(newOrder);

	if(ModelState.IsValid){
		newOrder.Username = User.Identity.Name;
		newOrder.OrderDate = DateTime.Now;
		storeDB.Orders.Add(newOrder);
		storeDB.SaveChanges();

		// process the order:
		var cart = ShoppingCart.GetCart(this);
		cart.CreateOrder(newOrder);
		return RedirectToAction("Complete", new { id = newOrder.OrderId });
	}
	// invalid - redisplay with errors:
	return View(newOrder);
}

ModelState

  1. MSDN - System.Web.Mvc.ModelStateDictionary 类 - 表示有关将已发送窗体绑定到操作方法(其中包括验证信息)的尝试的状态。

向 ModelState (模型状态字典) 中添加错误信息

[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
	var album = storeDB.Albums.Find(id);
	ModelState.AddModelError("Title", "What a terrible name!");
	return View(album);
}

ModelState (模型状态字典) 常用代码

//摘自:《ASP.NET MVC 3 高级编程》Page 122:
ModelState.IsValid == false
ModelState.IsValidField("LastName") == false
ModelState("LastName").Errors.Count > 0
var lastNameErrorMessage = ModelState("LastName").Errors[0].ErrorMessage;
@Html.ValidationMessageFor(m => m.LastName)

生产代码备份

public ActionResult Query(string bookCodeName)
{
    if(string.IsNullOrWhiteSpace(bookCodeName)) {
        return View();
    }
    BookCode bookCode = CommonBll.Where<BookCode>(e => e.BookCodeName == bookCodeName).FirstOrDefault();
    if(bookCode == null) {
        ModelState.AddModelError("BookCodeName", "This Book Code does not exist.");
        return View();
    }
    ViewBag.book = CommonBll.GetByKey<Book>(bookCode.BookID);
    return View(bookCode);
}

ModelState - 生产代码

曾计划在同一页面中,提供 "使用 Email 登录" 与 "使用 Email 与 Pw 登录" 2个选择。
当时共用 1 个验证模型类,该类有 Email 与 Password 两个属性。
当 "使用 Email 登录" 时,提交的数据中没有 Password,因此编写了以下代码,仅验证 2 个属性中的 1 个:

//MVC 模型绑定本 Action 的参数时,在 Form、QueryString 等处均未发现任何键为 Password 的数据,会导致 ModelState.IsValid 为 false。因此,下面仅检查 Email 的模型验证结果:

if(!ModelState.ContainsKey("Email") ||
    ModelState["Email"].Errors.Count != 0) {
    throw new T.ExitImmediately_Exception(
        T.Ex._MsgErr,
        "20130821215106",
        T.CharAndStr.SplicePropertiesToString(model)
    );
}

显示 验证信息 - ValidationSummary, AddModelError, ValidationMessageFor

结论 - Tony 常用代码

@Html.ValidationSummary(true)
ModelState.AddModelError(string.Empty, "ErrMsg");

AddModelError

public void AddModelError(string key, string errorMessage)
共 2 个重载,通常在 xxxController.cs 文件中使用。例如:

ModelState.AddModelError(key, errorMessage);

测试记录

调用此方法时,key 实参可分为 3 种情况:

  • 为 null,将抛出 System.ArgumentNullException。
  • 为 string.Empty,则无论 ValidationSummary() 的 excludePropertyErrors 实参为 true 还是 false,ValidationSummary() 总是会向 HTML 中输出 AddModelError() 的 errorMessage 实参。
  • 为非空的 key,无论此 key 实现在 ModelState 中是否存在同名的键,都仅当 ValidationSummary() 的 excludePropertyErrors 实参为 false 时,ValidationSummary() 才向 HTML 中输出 AddModelError() 的 errorMessage 实参。

换而言之:
excludePropertyErrors 为 true 时,仅显示以下方式添加的 errorMessage 实参,因为它的 key 为 string.Empty:

ModelState.AddModelError(string.Empty, errorMessage);

ValidationSummary

public static MvcHtmlString ValidationSummary(this HtmlHelper htmlHelper, bool excludePropertyErrors, string message, object htmlAttributes)
共 8 个重载,通常在 xxx.cshtml 文件中使用,例如:

@Html.ValidationSummary(false)

测试记录

除非 message 实参为空,否则本方法的输出中,总是以该实参开头 (无论 excludePropertyErrors 实参为 true 还是 false)。

ValidationMessageFor

public static MvcHtmlString ValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, object htmlAttributes)
共 4 个重载,通常在 xxx.cshtml 文件中使用,例如:

@Html.ValidationMessageFor(model => model.Email)

测试记录

如果添加如下键:
ModelState.AddModelError("Ky", "ErrMsg");
而此处也有同名的键:
@Html.ValidationMessageFor(model => model.Ky)
则显示上面添加的 ErrMsg

ASP.NET MVC 中的客户端验证 - jquery.validate.js & jquery.validate.unobtrusive.js

详见本站专文。

MetadataType

详见本站专文。

验证 DateTime

2015-11-05 Tony 测试记录

  • Model 中类型为 DateTime 的属性,即使未附加任何 Attribute,MVC 框架也会进行服务器与客户端双重验证。
  • 对于 DateTime? 仅验证是否为合法的日期时间格式。
  • 对于 DateTime 除了验证是否为合法的日期时间格式,还会验证是否为空。
  • 这种自动验证、以及 [DataType(DataType.Xxx)] 的验证,其错误信息似乎只能通过修改资源文件的途径来自定义

为了自定义错误信息,只好采用以下方式验证 DateTime (以下为生产代码):

using System;
using System.ComponentModel.DataAnnotations;

namespace FC.CS.LibraryManagement.Model.LibraryManagement
{
    public class BookListFilter
    {
        [RegularExpression(@"^ *\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}([T ]\d{1,2}:\d{1,2}(:\d{1,2})?)? *$", ErrorMessage = "The start date is invalid.")]
        public DateTime? DateOfPublication_Start { get; set; }

        [RegularExpression(@"^ *\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}([T ]\d{1,2}:\d{1,2}(:\d{1,2})?)? *$", ErrorMessage = "The end date is invalid.")]
        public DateTime? DateOfPublication_End { get; set; }
    }
}

Resource

博客园 Artech (蒋金楠)

  1. ASP.NET MVC 下的四种验证编程方式 - 手工验证、继承 ValidationAttribute、实现 IDataErrorInfo、实现 IValidatableObject。
  2. ASP.NET MVC 下的四种验证编程方式 - 续篇
  3. ASP.NET MVC 基于标注特性的 Model 验证: ValidationAttribute
  4. ASP.NET MVC 基于标注特性的 Model 验证: DataAnnotationsModelValidator
  5. ASP.NET MVC 基于标注特性的 Model 验证: DataAnnotationsModelValidatorProvider
  6. ASP.NET MVC 基于标注特性的 Model 验证: 将 ValidationAttribute 应用到参数上
  7. ASP.NET MVC 基于标注特性的 Model 验证: 一个 Model,多种验证规则
  8. ASP.NET MVC 如何实现自定义验证 (服务端验证 + 客户端验证)
  9. ASP.NET MVC 的客户端验证: jQuery 的验证
  10. ASP.NET MVC 的客户端验证: jQuery 验证在 Model 验证中的实现

博客园 zhangkai2237

  1. ASP.NET MVC3 数据验证 (一)
  2. ASP.NET MVC3 数据验证 (二) 错误信息的自定义及其本地化
  3. ASP.NET MVC3 数据验证 (三) 自定义数据注解

Internet

  1. ASP.NET MVC 表单验证方式总结
  2. ASP.NET MVC jQuery Validate 表单验证的多种方式
  3. jQuery 验证控件 jQuery.validate.js 使用说明+中文API
  4. ASP.NET MVC 数据验证 示例
  5. ASP.NET MVC 模型 部分验证
  1. RequiredAttributeBindRequiredAttribute