Model Binder 是 ASP.NET MVC 將 HTTP 請求資料(表單欄位、查詢字串、路由參數)自動轉換為 Action 方法參數物件的核心機制。掌握自訂 Model Binder 可處理複雜型別、特殊格式解析、資料轉換與驗證邏輯集中化。
Book book)
2. DefaultModelBinder 依參數名稱在 ValueProvider 中尋找對應值
3. 對簡單型別直接轉換;複雜型別遞迴繫結屬性
4. 繫結完成後執行模型驗證(DataAnnotations)
user[name]、items[0].id)public class BookModelBinder : IModelBinder {
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
// 1. 從 ValueProvider 取得原始值
var titleResult = bindingContext.ValueProvider.GetValue("Title");
var authorResult = bindingContext.ValueProvider.GetValue("Author");
var priceResult = bindingContext.ValueProvider.GetValue("Price");
// 2. 驗證必要欄位
if (titleResult == null || string.IsNullOrEmpty(titleResult.AttemptedValue)) {
bindingContext.ModelState.AddModelError("Title", "書名不可為空");
return null;
}
// 3. 型別轉換與預設值處理
decimal price = 0;
if (priceResult != null) {
decimal.TryParse(priceResult.AttemptedValue, out price);
}
// 4. 建構並回傳模型物件
return new Book {
Title = titleResult.AttemptedValue,
Author = authorResult?.AttemptedValue ?? "佚名",
Price = price,
CreatedAt = DateTime.Now
};
}
}
// Global.asax Application_Start
protected void Application_Start() {
// 針對特定型別註冊
ModelBinders.Binders.Add(typeof(Book), new BookModelBinder());
// 或全域取代預設繫結器
// ModelBinders.DefaultBinder = new CustomDefaultModelBinder();
}
[HttpPost]
public ActionResult Create(Book book) { // 自動使用 BookModelBinder
if (ModelState.IsValid) {
repository.Add(book);
return RedirectToAction("Index");
}
return View(book);
}
public class TrimStringModelBinder : DefaultModelBinder {
protected override void SetProperty(ControllerContext controllerContext,
ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor, object value) {
if (propertyDescriptor.PropertyType == typeof(string) && value is string str) {
value = str.Trim(); // 所有字串屬性自動 Trim
}
base.SetProperty(controllerContext, bindingContext, propertyDescriptor, value);
}
}
註冊:ModelBinders.Binders.Add(typeof(string), new TrimStringModelBinder());(謹慎使用,影響全域)
Model Binder 負責「資料轉換與填充」,Model Validator 負責「業務規則驗證」。兩者分工明確:
// 觀察 ValueProvider 內容
foreach (var key in bindingContext.ValueProvider.Keys) {
var val = bindingContext.ValueProvider.GetValue(key);
Debug.WriteLine($"{key} = {val.AttemptedValue}");
}