Mvc自定义验证

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

public class BookInfo
    {

        public string Name { get; set; }

        public string publisher { get; set; }
    }

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

        [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必须");
            }
        }

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

 

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

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

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

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

  刚才咱们也分析了,处理时,实际上是根据请求动做来区分调用哪一个方法的,那么咱们须要打上请求动做的标签。string

  若是没有标签咱们看看是什么个状况。报错了。it

  看看错误内容,方法调用不明确。这个实际上是路由解析的相关问题,关于路由解析,这里就很少作解释了,你们能够简单的理解为,io

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

  在稍做深刻,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是如何为咱们自定义校验工做的了。

相关文章
相关标签/搜索