本书《视图模型》这一章所讲内容在前面均有提及且未作更深入讲解故略过,进入下一章:
一、服务器端验证:
无论客户端验证与否,都应该执行服务器端验证。因为用户可能会禁用JavaScript或者做一些意想不到的事情来绕过客户端验证,而服务器验证是保护数据、防止劣质输入的最后一道防线。有些验证规则也需要服务器端进行处理,如网络拓扑可能会要求只有服务器才能访问对输入进行验证所需要的某些外部资源。
1.Data Annotations验证:[本节内容前面亦有提及]
Data Annotations的注解属性不只控制验证还有一些用于新型的模板特性,如DisplayName和DataType注解属性。专用于控制验证的注解属性如下表:
ValidationSummary扩展方法提供了验证错误的摘要列表,通常显示在表单的顶部。对于特定模型属性的验证错误,可以使用ValidationMessage和基于表达式的ValidationMessageFor方法。
MVC验证引擎会把验证错误放在ModelState中,将任何已有的错误都聚合成IsValid属性。
2.扩展ModelMetadataProvider:
在之前代码的Create动作对应页面显示如下图:
如果我们希望DateAdded显示为Date Added,可以使用DisplayNameAttribute注解属性设置。但是因为显示带有单词空格的属性名是一种通用需求,因此我们可以通过扩展ModelMetadataProvider类实现。
ModelMetadataProvider抽象类:
1 public abstract class ModelMetadataProvider 2 { 3 public abstract IEnumerable<ModelMetadata> GetMetadataForProperties( 4 Object container, 5 Type containerType 6 ); // 获取模型的每个属性所对应的 ModelMetadata 7 public abstract ModelMetadata GetMetadataForProperty( 8 Func<Object> modelAccessor, 9 Type containerType, 10 string propertyName 11 ); // 获取指定属性的ModelMetadata 12 public abstract ModelMetadata GetMetadataForType( 13 Func<Object> modelAccessor, 14 Type modelType 15 ); // 获取指定模型访问器和模型类型的ModelMetadata 16 }
为了定制特定属性的显示文本我们只需要重写DataAnnotationsModelMetadataProvider类的CreateMetadata方法:
1 namespace Guestbook 2 { 3 public class ConventionProvider:DataAnnotationsModelMetadataProvider 4 { 5 protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, 6 Type containerType, 7 Func<object> modelAccessor, 8 Type modelType, 9 string propertyName) 10 { 11 var meta=base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); 12 if (meta.DisplayName == null)//由于可能会用注解属性重写显示名称,我们只在显示名称未设置时修改其行为 13 { 14 meta.DisplayName = meta.PropertyName.ToSeparatedWords(); 15 } 16 return meta; 17 } 18 } 19 }
ToSeparatedWords扩展方法是将Pascal式的大小写标识符分成个别单词:
1 namespace Guestbook 2 { 3 public static class StringExtensions 4 { 5 public static string ToSeparatedWords(this string value) 6 { 7 if (value != null) 8 return Regex.Replace(value, "([A-Z][a-z]?)", " $1").Trim(); 9 return null; 10 } 11 } 12 }
然后修改Global.asax文件:
1 namespace Guestbook 2 { 3 public class MvcApplication : System.Web.HttpApplication 4 { 5 protected void Application_Start() 6 { 7 AreaRegistration.RegisterAllAreas(); 8 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 9 RouteConfig.RegisterRoutes(RouteTable.Routes); 10 BundleConfig.RegisterBundles(BundleTable.Bundles); 11 ModelMetadataProviders.Current = new ConventionProvider(); 12 } 13 } 14 }
现在运行已经如下图所示啦:
二、客户端验证:
1.客户端验证初步:
书中讲为了启用客户端验证,需要:
1)添加jquery.js、jquery.validate.js、jquery.validate.unobtrusive.js引用;
2)在web.config中添加配置:
<appSettings> <add key="ClientValidationEnabled" value="true" /> <add key="UnobtrusiveJavaScriptEnabled" value="true" /> </appSettings>
3)添加data标签属性,如下:
<input class="text-box single-line" data-val="true" data-val-required="The Name field is required." id="Name" name="Name" type="text" value=""/>
但是在MVC 5中,这些工作貌似给自动完成了,不再需要自己动手。。。我说的对吗?
2.使用RemoteAttribute:
这是一个远程验证注解属性。在用户提交表单之前会在服务器端对该模型属性执行远程验证,并在有验证错误的情况下显示错误信息,并拒绝递交表单。其好处是可以执行丰富的验证逻辑或客户端不能实现的验证逻辑,但这种远程验证也会影响性能,因为在验证期间包含了与远程服务器的通信、验证过程的执行以及验证结果的反馈。以Create动作为例:
1)添加Age属性、修改视图同时为方便删除数据库(因为表结构改变):
namespace Guestbook.Models { public class GuestbookEntry { public int Id { get; set; } [Required] public string Name { get; set; } [Required] [Remote("IsNumberEven", "Guestbook", ErrorMessage = "必须输入偶数")] public int Age { get; set; } [Required] public string Message { get; set; } public DateTime DateAdded { get; set; } } }
2)在控制器中添加方法:
public JsonResult IsNumberEven(int evenNumber) { return Json(evenNumber % 2 == 0, JsonRequestBehavior.AllowGet); }
该动作检查此数值是否是偶数,并返回一个以JsonResult进行封装的布尔型值。
但是为什么添加RemoteAttribute后点击提交就没有反应了呢?难道是MVC 5不支持此属性吗?
3.创建自定义客户端验证器:
这节没看懂,暂时跳过。。。
本章好失败。。。