假设我们书店需要录入一本书,为了简单的体现我们的自定义验证,我们的实体定义的非常简单,就两个属性,一个名称Name,一个出版社Publisher。

public class BookInfo
{ public string Name { get; set; } public string publisher { get; set; }
}

  Ok,需求有了,实体有了,那么添加我们的控制器和视图。先把代码贴出来。稍后我们在做分析

        [HttpGet]
public ActionResult Index()
{
return View(new BookInfo());
} //[HttpPost]
public ActionResult Index(BookInfo book)
{
Validate(book);
if (!ModelState.IsValid)
{
return View(book);
}
else
{
return Content("验证未通过!");
}
} private void Validate(BookInfo book)
{
if (string.IsNullOrEmpty(book.Name))
{
ModelState.AddModelError("Name","Name必须");
}
}

  视图就直接使用添加的强类型视图即可。 

 

  其实最开始我们可能想不到那么多,可能是这个样子滴

public ActionResult Index(BookInfo book)
{
Validate(book);
if (!ModelState.IsValid)
{
return View(book);
}
else
{
return Content("验证未通过!");
}
}    

  如果直接这么写,直接打开页面,你会发现页面显示的时候就会出现我们的校验信息。显然是不正确滴。
  

  分析一下,直接请求页面的时候,显然是通过Url输入的Get请求访问的我们的Action,那么这个时候是不需要校验滴。
  只有在我们表单提交的时候才需要验证,这个时候为post的请求。也就是这么一个action是搞不定的 ,我们需要分开处理。

  刚才我们也分析了,处理时,其实是根据请求动作来区分调用哪个方法的,那么我们需要打上请求动作的标签。

  如果没有标签我们看看是什么个情况。报错了。

  看看错误内容,方法调用不明确。这个其实是路由解析的相关问题,关于路由解析,这里就不多做解释了,大家可以简单的理解为,

  根据路由表,解析出我们的Controller为Home,Action为Index,根据Action的名称查找到两个方法,此时运行时
  只根据名称无法区这两个方法,就会报错了。
  为了让运行时能够区分请求类型,我们打上请求动作标签。ok,现在可以继续了
  这样就完成了验证。  

  在稍作深入,ModelState是坨What,为什么直接用它的IsValid就能判断校验。它其实就是Controller的一个ModelStateDictionary类型的属性。

  以下是ModelStateDictionary定义
  

[Serializable]
public class ModelStateDictionary : IDictionary<string, ModelState>, ICollection<KeyValuePair<string, ModelState>>, IEnumerable<KeyValuePair<string, ModelState>>, IEnumerable
{
public ModelStateDictionary();
public ModelStateDictionary(ModelStateDictionary dictionary);
public void Add(KeyValuePair<string, ModelState> item);
public void Add(string key, ModelState value);
public void AddModelError(string key, Exception exception);
public void AddModelError(string key, string errorMessage);
public void Clear();
public bool Contains(KeyValuePair<string, ModelState> item);
public bool ContainsKey(string key);
public void CopyTo(KeyValuePair<string, ModelState>[] array, int arrayIndex);
public IEnumerator<KeyValuePair<string, ModelState>> GetEnumerator();
public bool IsValidField(string key);
public void Merge(ModelStateDictionary dictionary);
public bool Remove(KeyValuePair<string, ModelState> item);
public bool Remove(string key);
public void SetModelValue(string key, ValueProviderResult value);
public bool TryGetValue(string key, out ModelState value);
IEnumerator IEnumerable.GetEnumerator();
public int Count { get; }
public bool IsReadOnly { get; }
public bool IsValid { get; }
public ICollection<string> Keys { get; }
public ICollection<ModelState> Values { get; }
public ModelState this[string key] { get; set; }
}

  就看我们用到的方法

  

public bool IsValid
{
get
{
return Enumerable.All<ModelState>((IEnumerable<ModelState>) this.Values, (Func<ModelState, bool>) (modelState => modelState.Errors.Count == 0));
}
}

  

public void AddModelError(string key, string errorMessage)
{
this.GetModelStateForKey(key).Errors.Add(errorMessage);
} private ModelState GetModelStateForKey(string key)
{
if (key == null)
throw new ArgumentNullException("key");
ModelState modelState;
if (!this.TryGetValue(key, out modelState))
{
modelState = new ModelState();
this[key] = modelState;
}
return modelState;
}

  

public class ModelState
{
private ModelErrorCollection _errors = new ModelErrorCollection(); public ValueProviderResult Value { get; set; } public ModelErrorCollection Errors
{
get
{
return this._errors;
}
}
}

  看看代码,哦,基本上明白了,ModelState记录了一个Errors集合,我们校验的时候会增加添加错误信息。

  IsValid就判断了字典中的所有ModelState的Error集是否都为空。

  再来猜一下Dictionary中的Key是什么呢。猜测就应该是对应的校验字段名。来做个试验,把我们添加错误信息的Name键,改为Publisher试试什么效果。

  

   嗯,跟预期的一样。现在就明白了Mvc是如何为我们自定义校验工作的了。

Mvc自定义验证的更多相关文章

  1. ASP.NET MVC自定义验证Authorize Attribute(包含cookie helper)

    前几天Insus.NET有在数据库实现过对某一字段进行加密码与解密<使用EncryptByPassPhrase和DecryptByPassPhrase对MS SQLServer某一字段时行加密和 ...

  2. ASP.NET MVC自定义验证Authorize Attribute

    前几天Insus.NET有在数据库实现过对某一字段进行加密码与解密<使用EncryptByPassPhrase和DecryptByPassPhrase对MS SQLServer某一字段时行加密和 ...

  3. MVC自定义验证 jquery.validate.unobtrusive

    MVC的验证 jquery.validate.unobtrusive 阅读目录 一.应用 二.验证规则 1.一.简单规则 2.二.复杂一点的规则 3.三.再复杂一点的规则(正则) 4.四.再再复杂一点 ...

  4. MVC数据验证原理及自定义ModelValidatorProvider实现无编译修改验证规则和错误信息

    Asp.net MVC中的提供非常简单易用的数据验证解决方案. 通过System.ComponentModel.DataAnnotations提供的很多的验证规则(Required, StringLe ...

  5. Asp.net MVC验证那些事(4)-- 自定义验证特性

    在项目的实际使用中,MVC默认提供的Validation Attribute往往不够用,难以应付现实中复杂多变的验证需求.比如, 在注册用户的过程中,往往需要用户勾选”免责声明”,这个checkbox ...

  6. ASP.NET MVC验证 - 自定义验证规则、验证2个属性值不等【待验证】

    提示:保存后才提示错误信息 自定义验证特性,继承ValidationAttribute并实现IClientValidatable 这次重写了基类的IsValid()方法的另外一个重载,因为该重载包含了 ...

  7. ASP.NET MVC 3 使用Model自定义验证的样式

    1.修改jquery.validate.unobtrusive.js 将onError方法修改 //修改的部分 //////////////////////////////////////////// ...

  8. MVC 自定义过滤器/特性来实现登录授权及验证

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精    最近在做自学MVC,遇到的问题很多,索性一点点总结 ...

  9. ASP.NET MVC如何实现自定义验证(服务端验证+客户端验证)

    ASP.NET MVC通过Model验证帮助我们很容易的实现对数据的验证,在默认的情况下,基于ValidationAttribute的声明是验证被使用,我们只需 要将相应的ValidationAttr ...

随机推荐

  1. 《学习记录》ng2-bootstrap中的component使用教程

    前序: 现在angular2已经除了集成的angular-cli,建议大家可以基于这个来快速开发ng2的项目,不用自己再搭建环境: 相关内容请前往:https://angular.cn/docs/ts ...

  2. 2017-3-9 SQL server 数据库

    数据库的定义:数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,简单说数据库是一些存储在硬盘上的数据文件,随着信息技术和市场的发展,数据管理不再仅仅是存储和管理数据,而转变成用户所 ...

  3. Hibernate学习笔记①

    ---恢复内容开始--- 1.JavaEE的三层结构 WEB层--Service层--DAO层 2.Hibernate版本 Hibernate3.x  4.x  5.x 4版本是过渡版本 不使用  5 ...

  4. ReactJS React+Redux+Router+antDesign通用高效率开发模板,夜间模式为例

    工作比较忙,一直没有时间总结下最近学习的一些东西,为了方便前端开发,我使用React+Redux+Router+antDesign总结了一个通用的模板,这个技术栈在前端开发者中是非常常见的. 总的来说 ...

  5. eclipse中以debug方式启动tomcat报错

    在eclipse中debug  Tomcat报错,错误如下: FATAL ERROR in native method: JDWP No transports initialized, jvmtiEr ...

  6. 不可重入定时器Newlife.TimerX

    在.net常用的定时器类有下面三种,使用定时器时需要设定参数,如间断时间.定时器计溢出后的回调函数.延时.开始等,定时器的的主要方法有开始.终止等,不同的定时器实现上述的方法会有一些差异,本文会针对具 ...

  7. Android之XListView下拉刷新,更新网络美女图

    一.简介:   下拉刷新是一种特定的手动刷新交互,和其他的同类操作不同的地方在于它采用了更加直觉的下拉操作,所以它的交互足够清晰明显. 下拉刷新主要用在类似ListView这样的控件,设计下拉刷新有三 ...

  8. Linux下的文件描述符

    文件描述符是一个简单的整数,用以标明每一个被进程所打开的文件和socket.第一个打开的文件是0,第二个是1,依此类推.Unix 操作系统通常给每个进程能打开的文件数量强加一个限制.更甚的是,unix ...

  9. 【iOS】7.4 定位服务->3.1 地图框架MapKit 功能1:地图展示

    > 本文并非最终版本,如果想要关注更新或更正的内容请关注文集,联系方式详见文末,如有疏忽和遗漏,欢迎指正. --- > 本文相关目录: ================== 所属文集:[[ ...

  10. Kubernetes日志收集

    关于kubernetes的日志分好几种,针对kubernetes本身而言有三种: 1.资源运行时的event事件.比如在k8s集群中创建pod之后,可以通过 kubectl describe pod ...