Asp.net MVC的Model Binder工作流程以及擴展方法(3) - DefaultModelBinder


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不同的地方

mvc_default_model_binding_flow

二,覆蓋方法,改變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 ();
}

 


免責聲明!

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



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