zoukankan      html  css  js  c++  java
  • Mvc自定义验证

      假设我们书店需要录入一本书,为了简单的体现我们的自定义验证,我们的实体定义的非常简单,就两个属性,一个名称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是如何为我们自定义校验工作的了。

  • 相关阅读:
    centos 8.5设置nginx开机自动启动
    python利用Faker模块造测试数据(转载)
    结构化分析建模
    关于使用com.anjiplus依赖实现的验证码功能在linux服务器上失效的问题
    vue 子组件提交接口,父组件刷新数据
    vue 全局钩子:路由守卫
    Scala函数式编程基础
    Flink
    Scala面向对象编程
    Scala运算符
  • 原文地址:https://www.cnblogs.com/superCow/p/3794347.html
Copyright © 2011-2022 走看看