ASP.NET MVC系列:Model


1. Model任務

  Model負責通過數據庫、AD(Active Directory)、Web Service及其他方式獲取數據,以及將用戶輸入的數據保存到數據庫、AD、Web Service等中。

  Model只專注於有效地提供數據訪問機制、數據格式驗證、業務邏輯驗證等。

2. 定義Model Metadata

  Metadata用於定義數據模型的相關屬性,如:顯示名稱、數據長度及數據格式驗證等。利用System.ComponentModel.DataAnnotations中的DataAnnotations機制對ASP.NET MVC數據模型進行輔助定義。

  System.ComponentModel.DataAnnotations命名空間的驗證屬性包括:StringLength、Required、RegularExpression及Range等。

  示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace Libing.Portal.Web.Models
{
    public class Product
    {
        public int ProductID { get; set; }

        [DisplayName("產品名稱")]
        [Required(ErrorMessage = "產品名稱不能為空")]
        [StringLength(100, ErrorMessage = "產品名稱最大長度100個字符")]
        public string ProductName { get; set; }

        [Required]
        [RegularExpression(@"^\d+$", ErrorMessage = "庫存數量只能為數字")]
        [Range(0, 100, ErrorMessage = "庫存數量0至100之間")]
        public int UnitsInStock { get; set; }
    }
}

3. 自定義Metadata驗證屬性

  定義Metadata驗證屬性:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.ComponentModel.DataAnnotations;

namespace Libing.Portal.Web.Models.Attributes
{
    /// <summary>
    /// 驗證正整數
    /// </summary>
    public class PositiveIntegerAttribute : RegularExpressionAttribute
    {
        public PositiveIntegerAttribute() :
            base(@"^\d+$") { }
    }
}

  使用自定義Metadata驗證屬性:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

using Libing.Portal.Web.Models.Attributes;

namespace Libing.Portal.Web.Models
{
    public class Product
    {
        [Required]
        [PositiveInteger(ErrorMessage = "庫存數量只能為正整數")]
        [Range(0, 100, ErrorMessage = "庫存數量0至100之間")]
        public int UnitsInStock { get; set; }
    }
}

4. 模型綁定

  ASP.NET MVC通過模型綁定(Model Binding)機制來解析客戶端傳送過來的數據,解析的工作由DefaultModelBinder類進行處理。若要自定義ModelBinder類行為,需實現IModelBinder接口。

4.1 簡單模型綁定

  Action的參數在Action被執行時會通過DefaultModelBinder從form或QueryString傳送過來的數據進行處理,即將傳送過來的字符串型的數據轉換成對應的.Net類,並將其輸入Action。

public ActionResult Index(string UserName)
{
    ViewBag.UserName = UserName;
    return View();
}

4.2 復雜模型綁定

  在ASP.NET MVC中,可以通過DefaultModelBinder類將form數據對應到復雜的.NET類,即模型。該模型可能是一個List<T>類或一個含有多個屬性的自定義類。

public ActionResult Index(Product product)
{
    ViewBag.ProductName = product.ProductName;
    return View();
}

  從客戶端傳送過來的form數據會通過DefaultModelBinder類自動創建Product類對象,將form字段通過.NET的Reflection機制一一對應到對象的同名屬性中。

4.3 模型綁定數據驗證

  ASP.NET MVC在處理模型綁定時,會處理Model的數據驗證。模型綁定的數據驗證失敗,則Controller的ModelState.IsValid驗證值為false。

[HttpPost]
public ActionResult Create(Product product)
{
    if (ModelState.IsValid)
    {
        return RedirectToAction("Details", new { id = product.ProductID });
    }

    return View();
}

  可以使用ModelState.AddModelError()方法在Controller中判斷更加復雜的業務邏輯,並自定義錯誤信息至ModelState。

[HttpPost]
public ActionResult Create(Product product)
{
    if (ModelState.IsValid)
    {
        if (product.UnitsInStock <=10)
        {
            ModelState.AddModelError("UnitsInStock", "UnitsInStock必須大於10");
            return View();
        }

        return RedirectToAction("Details", new { id = product.ProductID });
    }

    return View();
}

4.4 使用Bind屬性限制可被更新的Model屬性

  復雜模型綁定的驗證,在默認情況下,不管Model中有多少字段,只要客戶端form有數據傳送過來就會自動進行綁定。在ASP.NET MVC中可以通過使用Bind屬性限制可被更新的Model屬性。

4.4.1 綁定多個字段中的部分字段

  通過Bind屬性來定義Model中需要綁定哪些字段。

  示例:不包括的自動綁定的屬性

[HttpPost]
public ActionResult Create([Bind(Exclude = "ProductID")] Product product)
{
    if (ModelState.IsValid)
    {
        if (product.UnitsInStock <= 10)
        {
            ModelState.AddModelError("UnitsInStock", "UnitsInStock必須大於10");
            return View();
        }

        return RedirectToAction("Details", new { id = product.ProductID });
    }

    return View();
}

  示例:多個不包括的自動綁定的屬性

  多個字段需要排除,使用逗號(,)分隔。

[HttpPost]
public ActionResult Create([Bind(Exclude = "ProductID,CreateDate")] Product product)
{
    if (ModelState.IsValid)
    {
        if (product.UnitsInStock <= 10)
        {
            ModelState.AddModelError("UnitsInStock", "UnitsInStock必須大於10");
            return View();
        }

        return RedirectToAction("Details", new { id = product.ProductID });
    }

    return View();
}

  示例:使用Include指定需要綁定的字段

[HttpPost]
public ActionResult Create([Bind(Include = "ProductName,UnitsInStock")] Product product)
{
    if (ModelState.IsValid)
    {
        if (product.UnitsInStock <= 10)
        {
            ModelState.AddModelError("UnitsInStock", "UnitsInStock必須大於10");
            return View();
        }

        return RedirectToAction("Details", new { id = product.ProductID });
    }

    return View();
}

  如果不希望在每個Action的參數中都應用Bind屬性,可以在Model定義中指定。

  示例:在Model中設置Bind屬性

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Web.Mvc;

namespace Libing.Portal.Web.Models
{
    [Bind(Include = "ProductName,UnitsInStock")]
    public class Product
    {
        public int ProductID { get; set; }

        public string ProductName { get; set; }

        public int UnitsInStock { get; set; }

        public DateTime CreateDate { get; set; }
    }
}

4.4.2 UpdateModel()方法與TryUpdateModel()方法

  當綁定引發異常時,使用UpdateModel()方法會直接拋出異常。使用TryUpdateModel()方法,則會在驗證成功時返回true,失敗或發生異常時返回false。

  示例:UpdateModel()

[HttpPost]
public ActionResult Create(Product product)
{
    UpdateModel(product);

    return RedirectToAction("Details", new { id = product.ProductID });
}

  示例:TryUpdateModel()

[HttpPost]
public ActionResult Create(Product product)
{
    if (TryUpdateModel(product))
    {
        return RedirectToAction("Details", new { id = product.ProductID });
    }

    return View();
}

5. ViewBag與ViewModel

5.1 使用ViewBag

  Controller基類提供了ViewBag,可用於將數據項從Controller傳遞到View中。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using Libing.Portal.Web.Models;

namespace Libing.Portal.Web.Controllers
{
    public class ProductController : Controller
    {
        private PortalContext context = new PortalContext();

        public ActionResult Edit(int id)
        {
            Product product = context.Products.Find(id);
            ViewBag.Categories = new SelectList(context.Categories, "CategoryID", "CategoryName", product.CategoryID);

            return View(product);
        }

        protected override void Dispose(bool disposing)
        {
            context.Dispose();
            base.Dispose(disposing);
        }
    }
}
@Html.DropDownList("CategoryID", ViewBag.Categories as SelectList)

5.2 使用ViewModel模式

  ViewModel模式創建強類型的類,對特定View情形優化,並向View模板提供所需要的動態值或內容。Controller將這些ViewModel傳遞到View模板中顯示。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Web.Mvc;

namespace Libing.Portal.Web.Models.ViewModels
{
    public class ProductViewModel
    {
        public Product Product { get; set; }

        public SelectList Categories { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using Libing.Portal.Web.Models;
using Libing.Portal.Web.Models.ViewModels;

namespace Libing.Portal.Web.Controllers
{
    public class ProductController : Controller
    {
        private PortalContext context = new PortalContext();

        public ActionResult Edit(int id)
        {
            Product product = context.Products.Find(id);

            ProductViewModel productViewModel = new ProductViewModel();
            productViewModel.Product = product;
            productViewModel.Categories = new SelectList(context.Categories, "CategoryID", "CategoryName", product.CategoryID);

            return View(productViewModel);
        }

        protected override void Dispose(bool disposing)
        {
            context.Dispose();
            base.Dispose(disposing);
        }
    }
}
@model Libing.Portal.Web.Models.ViewModels.ProductViewModel
@Html.DropDownList("CategoryID", Model.Categories)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM