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是如何爲咱們自定義校驗工做的了。

相關文章
相關標籤/搜索