Default Binder是MVC中的清道夫,把守着Model Binder中的最后一道防線。如果我們沒有使用Custom Model Binder等特殊處理,那么Model的綁定都是有Default Binder處理的。這篇文章,一起看看Default Binder和如何擴展Default Binder.
一,Default Binder的流程
下面的圖是Default Model Binder中的關鍵方法BindModel的代碼邏輯圖。
ValueProvider是包裝好的類似於字典容器,里面包含了所有request中能夠獲取到的值(無論是Form提交的,還是Querystring中的)
1. 假如我們綁定一個簡單的int參數,那么Default Binder會在ValueProvder中直接找到對應值,然后返回。
2. 如果綁定的是復雜類型(圖中的Complex Model),比如對象,則會遍歷每個屬性,然后綁定該屬性的值。如果屬性是簡單類型,就走上面的1流程;如果不是,就繼續進行2流程。
可以看出,Default Model Binder是一個比較復雜和巧妙的過程。在擴展Default Binder的時候,如果override BindeModel方法,不會全盤重寫,而是一個”修飾“的過程。
另外,在BindeModel過程中,有對於數據的驗證的,這是和我們之前介紹的Custom Model Binder和Binder Attribute不同的地方。
二,覆蓋方法,改變Default Binder行為
這里應用stackoverflow上的一個例子。原文地址: http://stackoverflow.com/questions/8729139/manipulate-model-value-before-passing-it-to-defaultmodelbinder-bindmodel
問題:
input中要求用戶輸入百分比值,但是不過分限定用戶輸入值的格式,比如用戶可以輸入50, 50%, 后台代碼希望提交綁定后的值是個decimal類型,也就是說,在用戶輸入50, 50%的情況下,后台代碼得到的是0.5
首先看看,屬性是如何定義的。下面代碼中的FooPercent 就是我們用來保存百分比的屬性。
[DataType("Percent")] [Display(Name = "Percent of foo completed")] [Range(0.0d, 1.0d, ErrorMessage="The field {0} must be between {1:P0} and {2:P0}.")] public decimal? FooPercent { get; set; }
接下來,創建PercentModelBinder繼承自DefaultModelBinder. 發現DataType是Percent的綁定對象,會先嘗試綁定。
public class PercentModelBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { if (bindingContext.ModelMetadata.DataTypeName == "Percent") { ValueProviderResult result = bindingContext.ValueProvider.GetValue( bindingContext.ModelName); if (result != null) { string stringValue = (string)result.ConvertTo(typeof(string)); decimal decimalValue; if (!string.IsNullOrWhiteSpace(stringValue) && decimal.TryParse( stringValue.TrimEnd(new char[] { '%', ' ' }), out decimalValue)) { return decimalValue / 100.0m; } } } return base.BindModel(controllerContext, bindingContext); } }
最后,替換MVC原有的DefaultModelBinder
protected void Application_Start() { ModelBinders.Binders.DefaultBinder = new PercentModelBinder (); }