在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
验证是ASP.NET MVC开发中一个非常重要的环节,包括客户端和服务端验证。幸好,MVC提供了非常简便的数据注解(Data Annotations)来帮助我们进行这项工作。 1.验证性的数据注解 MVC本身内置了一些常用的数据注解,像是Required,DisplayName等等,我会在下面一一讲解。 最常用的就是Required,像是下面这样:
使用Required可以指定错误消息: [Required(ErrorMessage = "First Name is required")] public string FirstName { get; set; } 使用Required是不够的,我们还需要规定用户的输入限制,像是字符串,就常有长度的限制,这时我们就可以利用StringLength。像是这样: [Required(ErrorMessage = "First Name is required")] [StringLength(160)] public string FirstName{ get; set;} 它规定了我们输入的最大长度是160个字符。如果想要规定最小长度,我们可以这样写: [Required(ErrorMessage = "First Name is required")] [StringLength(160, MinimumLength = 3)] public string FirstName { get; set; } 实际的效果如图: [Range(0.01, 100.0, ErrorMessage = "Price must be between 0.01 and 100.0")] public decimal Price { get; set; } Range()是一个双闭区间,就是说,包含0.01和100.0。 最后一个要讲的,就是RegularExpression。 我们可以这样使用: [Required(ErrorMessage = "Email is required")] [RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+[A-Za-z]{2,4}", ErrorMessage = "Email is not valid")] [DataType(DataType.EmailAddress)] public string Email { get; set; } 通过上面,我们可以知道,所有用于验证用的数据注解都可以自定义自己的错误消息。 2.显示性的数据注解 我们都注意到,变量FirstName在页面上的实际显示是:First Name。这样做才是符合实际需要的,要想这样做,我们就必须利用DisplayName: [Required(ErrorMessage = "First Name is required")] [DisplayName("First Name")] [StringLength(160, MinimumLength = 3)] public string FirstName { get; set; } 同样是为属性定义说明,还有另一种注解:Dispaly,它的作用并不仅仅是指定显示的内容,甚至能够指定显示的顺序,像是这样: [Required(ErrorMessage = "First Name is required")] [Display(Name = "First Name", order = 15000)] [StringLength(160)] public string FirstName { get; set; } order的默认参数是10000,如果其他变量并没有设置order值,FirstName就排在其他变量后面。但实际上是不用这么麻烦的,如果不指定该值,就会按照变量声明的顺序排列。 Display在用于属性的显示名称上,具有更高的优先级。 DisplayName专门用于定义属性的显示名称,但是Display并不仅仅是如此。它的内容非常丰富,有些在这里不好讲,而且本人是MVC新手,所以还请感兴趣的同学自己查一下相关资料。 如果对数据库有所了解的话,就会知道,数据库需要key值用于搜索相应的元组。MVC经常与数据库打交道,所以我们的模型中经常需要定义一个或几个名称中包含有Id的作为key的属性,像是OrderId之类的,但是我们在显示的时候又不想将这些属性显示出来,但正如我上面所讲的,默认是会将该模型的所有属性都显示出来。那该怎么办呢?就是对显示隐藏,我们可以使用HiddenInput。 像是这样: public class Person{ [HiddenInput] public string Name { get; set; } [HiddenInput(DisplayValue = false)] public string Sex { get; set; } public int Age { get; set; } } 然后是控制器: public ActionResult Index(){ Person person = new Person() { Name = "Jos", Sex = "man", Age = 18 }; return View(person); } 实际的效果如图: 我们可以看到,"Sex"完全被隐藏起来了! 使用了HiddenInput,默认情况下属性会以只读形式显示出来,像是上面的Name,要想完全隐藏,就得将DisplayValue设置为false。 我们可以来看看使用了HiddenInput的HTML: <div class = "editor-label"><label for = "Name">Name</label></div> <div class = "editor-label">Jos<input id = "Name" name = "Name" type = "hidden" value = "Jos"/></div> <input id = "Sex" name = "Sex" type = "hidden" value = "man"/> <div class = "editor-label"><label for = "Age">Age</label></div> <div class = "editor-field"? <input class = "text-box single-line" id = "Age" name = "Age" type = "text" value = "18"/> <div> 这些只要了解就好,MVC会自动帮我们处理。 特别强调一下,HiddenInput的命名空间是System.Web.Mvc。 同样是隐藏属性在HTML上的显示,我们还可以使用ScaffoldColumn特性。 使用ScaffoldColumn并不是为属性设置type = "hidden",它是直接将该属性从基架中删除。我们知道,MVC可以通过预定义模板来自动生成HTML,这种方式就是基架(Scaffolding)。ScaffoldColumn表示存在于基架中并最终呈现在HTML中的字典。 像是这样: [ScaffoldColumn(false)] public int OrderId { get; set; } 即使从基架中将该属性删除,模型绑定器仍然会试图为该属性赋值,这样就为典型的攻击“重复提交”提供了机会。黑客们可以试图向我们的网页中发送"OrderId = 100"这样的字段,而我们的模型绑定器会为该属性赋值并且有可能赋为黑客提供的值。要想防止这种攻击,我们可以利用Bind特性。 [Bind(Include = "Name, Comment")] public class Review{ public int ReviewId{ get; set;} public int ProductId{ get; set;} publc string Name{ get; set;} public string Comment{ get; set;} } 这样模型绑定器就只绑定Name和Comment属性。 [Bind(Exclude = "OrderId")] public partial class Order { [ScaffoldColumn(false)] public int OrderId { get; set; } [ScaffoldColumn(false)] public string UserName { get; set; } } 这样,上面所讲的“重复提交”攻击就无法发挥作用了。但是必须注意,使用"Include"的白名单比起使用"Exclude"的黑名单更加安全,因为我们永远也不知道黑客会用怎样的方式来攻击我们,但确定的是,我们可以知道哪些被绑定的属性是不会造成太大的危害的。 使用白名单还是黑名单还是得看具体情况,毕竟有时候我们需要绑定的属性非常多,如果采用白名单的方式,光是数据注解这里可能就要超过了我们该模型类的代码总量了。 Bind既可以用于模型,也可以用于控制器操作的参数,但更多时候还是用在模型上。 提到模型绑定器,这里就必须得说一下属性的更新问题。模型绑定器会更新被绑定的属性的值,但有些值我们可能希望它永远都不要被更新,那么我们就可以使用ReadOnly特性。 像是这样: [ReadOnly(true)] public decimal Total{ get; set;} 模型绑定器就不会更新它的值,虽然实际运行的时候,我们的确可以在文本框里修改它的值,但是该值并不会被用来更新该属性的值。 ReadOnly的命名空间是在using System.ComponentModel。 既然提到可读,那么一定存在可写。是的,在System.ComponentModel.DataAnnotations中就有一个Editable。 它的使用方式和ReadOnly完全一样,但我们会很好奇:如果同时将这两个注解用在同一个属性上,会怎么样呢?事实上,Editable拥有更高的优先级。 我们会在用户的登陆界面中要求用户输入登陆密码,但是又必须保证,这些密码不会显示出来以免被别人看到,这时,DataType就发挥作用了: [Required] [DataType(DataType.Password)] [DisplayName("Password")] public string Password { get; set; } 从上面可以看出,DataType所谓的数据类型,并不是我们常说的int,float等,事实上,DataType本身也有一个可支持的数据类型枚举: public enum DataType{ Custom, DateTime, Date, Time, Duration, DataType实际上是一个验证特性,它继承自ValidationAttribute,但我之所以放在这里讲,是因为所谓的"显示"性,是指它的作用效果,像DataType的作用效果就是为它内置的数据类型提供不同的显示效果。 [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple=false)] public class DataTypeAttribute : ValidationAttribute{ public DataTypeAttribute(DataType dataType); public DataTypeAttribute(string customDataType); public virtual string GetDataTypeName(); public override bool IsValid(object value); public string CustomDataType { get; } public DataType DataType { get; } public DisplayFormatAttribute DisplayFormat { get; } } 我们有时候想要对输出进行格式化设置,这时我们就可以利用DisplayFormat。 像是这样: [Required(ErrorMessage = "Price is required")] [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:c}")] [Range(0.01, 100.0, ErrorMessage = "Price must be between 0.01 and 100.0")] public decimal Price { get; set; } 就会有这样的效果:
话说,中文版的VS2012莫非真的是入乡随俗,我看到外国的教程都是美元标记,但这里却是RMB标记!但这点确实真的很重要,毕竟,在中国发布的网站价格标注的要是美元的话,那还真的是没有多少人会买了。 这里必须注意,ApplyFormatInEditMode的默认值是false,之所以这样,是因为我们模型绑定器无法解析格式化的值。 查看DisplayFormat的源码,我们就可以发现,它还有两个个布尔类型的属性:HtmlEncode和ConvertEmptyStringToNull,前者表示是否需要对目标内容进行HTML编码,默认下是true(这样是为了安全性的考虑),后者表示是否将传入的空字符串转换成Null。 DisplayFormat还有一个string属性:NullDisplayText,它表示针对空值(Null)对象的显示文本。 同样的道理,因为DataType也对应着一个DisplayFormatAttribute,所以当这两个特性同时应用在相同的元素上,后者具有更高级的优先级。 最后一个要讲的数据注解,因为不知道要放在哪里,但提到模板的话,就还是放在这里好了。它就是UIHintAttribute。 我们知道,HTML辅助方法会帮我们选择基于Model的模板方法。所谓的模板方法,指的是我们在通过调用这些方法来将Model的数据显示在View中时,采用默认或者指定的模板来决定最终呈现在浏览器中的HTML。这点在我们使用MVC的时候就已经察觉了:模板名称对应具体的Model元数据。所以,通过元数据,我们可以自定义要选择的模板。像是这样: public class Person{ [UIHint("Template A")] public string Name{ get; set;} [UIHint("Template B", "Mvc")] [UIHint("Template A")] 它有两个构造函数: public UIHintAttribute(string uiHint); public UIHintAttribute(string uiHint, string presentationLayer); 对于最后一个属性Sex,最终采用的是Template B,因为它的presentationLayer的值为Mvc。 本人完全是MVC新手,所讲的均是自己的理解,如果有说得不对的地方,还请各位大神指出。
|
请发表评论