iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 23
1

ASP.NET Core MVC 提供的模型繫結功能會自動將 HTTP 請求中的資料映射到對應的方法參數中。參數類型可以是基本資料型態(例如字串和整數)或複雜的 POCO 類別。如此一來,開發人員就不用在程式邏輯中把請求中的資料一個一個讀出來,再指定給對應的物件屬性。

繫結運作方式

MVC 的中介層在收到請求時,會將其路由到對應的 ControllerAction 中,並將 HTTP 請求中的資料自動繫結方法參數中。例如這個 URL:

/Todo/Edit/3

因為這段 URL 符合中介層中定義的 {controller=Home}/{action=Index}/{id?},所以會被路由到 Todo ControllerEdit Action 中,還會再接收一個非必填的 id 參數:

public class TodoController : Controller
{
    public IActionResult Edit(int? id)
    {
        return View();
    }
}

繫結時,MVC 會嘗試從請求的幾個部分來取得對應的資料:

  • Form Values:用 POST 發送的 HTTP 請求中包含的表單資料。
  • Route Values:在 MVC URL template 中設定的對應鍵值。
  • Query Strings:網址中的查詢字串。

會以由上到下 (Form > Route > Query String) 的順序來取值,取到資料後,就不會使用後面的資料。

繫結屬性

除了依照預設的順序來依序使用三個資料來源外,也可以用幾種 Attribute 來指定繫結的行為:

  • [BindRequired]:如果沒有繫結到被標註的參數會發生錯誤。
  • [BindNever]:忽略被標註參數的繫結。
  • [FromHeader]:由 HTTP Header 來繫結資料。
  • [FromQuery]:由 URL 查詢字串來繫結資料。
  • [FromRoute]:由路由定義的 URL 來繫結資料。
  • [FromForm]:由 HTTP POST 的表單來繫結資料。
  • [FromServices]:由 DI 注入資料。雖然一般都是從建構元來注入服務,但當一個類別要注入的服務太多的時候會滿容易搞亂的。這時候就可以透過這個方式把服務注入到方法參數中。
  • [FromBody]:由 HTTP Body 來繫結資料。
  • [ModelBinder]:用來覆寫預設的繫結行為。

模型驗證

在資料繫結的同時,也可以對資料格式做驗證,就不需要在程式邏輯中讓開發人員一個一個檢查了。設定驗證規則的方式也很簡單,只要加上對應規則的 Attribute 就可以了,例如下面的這個類別,我們在 Title 屬性加上 [Required] 代表為必填欄位,[StringLength(100)] 則代表字串最大長度是 100。官方文件中可以看到更多內建的驗證規則。

public class TodoViewModel
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }

    public DateTime CreatedAt { get; set; }

    public bool Completed { get; set; }
}

加上驗證屬性後,在驗證失敗時就可以看到對應的錯誤訊息。我們用這個 Controller 來試試看:

public class TodoController : Controller
{
    public IActionResult Validate([FromBody]TodoViewModel todo)
    {
        if (ModelState.IsValid)
        {
            return Ok();
        }

        return BadRequest(ModelState);
    }
}

https://ithelp.ithome.com.tw/upload/images/20181106/20107875TqdQQ8RRZt.png

參考資料


上一篇
Routing 路由
下一篇
Views 視圖
系列文
.Net Core 網站開發 10131
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言