Agenda
前言
MVC的Model-Binding
建立複雜物件(牽扯到複雜模型綁定.)
這篇會跟大家介紹MVC是如何把達成這個複雜的動作
我有做一個可以針對於Asp.net MVC Debugger的專案,只要下中斷點就可輕易進入Asp.net MVC原始碼.
IModelBinder(DefaultModelBinder)
DefaultModelBinder
將Http請求傳來資料轉換為強型別物件,DefaultModelBinder
是如何取得使用Model
資料呢?
實現
IValueProvider
來處理。
ModelBinders
IModelBinder.BindModel
方法使用兩個參數
1 | public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) |
ControllerContext
:Controller
資訊,ModelBindingContext
:當前參數綁定資訊
BindModel
方法機於Http
請求傳送資料進行Model
綁定(對於Action
方法使用參數),其中ModelBindingContext
參數會提供綁定使用的重要物件成員.
關於
ModelBindingContext
建立我們會在後續部分進行的單獨介紹.
在IModelBinder.BindModel
方法中主要透過兩個重要internal
方法.
BindComplexModel
:複雜參數綁定BindSimpleModel
:簡單參數綁定
下圖可以表示SimpleModel
和ComplexModel
ComplexModel
一個人可擁有多個房子,所以Person
類別擁有HouseCollection
引用.
取得使用ModelBinder
機制。
取得ModelBinder
會依照下面順序
- 參數掛有
ModelBinderAttribute
標籤並將BinderType
屬性指向一個繼承IModelBinder
型別. - 參數掛有繼承
CustomModelBinderAttribute
類型 - 透過
ModelBinderProviderCollection
(預設MVC沒有提供ModelBinderProvider
) - 預設
DefaultModelBinder
下面兩個使用ModelBinder
都是DefaultModelBinder
,但一個是使用第一點,另一個使用第四點.
1 | public ActionResult HttpModules(Person p) |
在Global.cs
可透過ModelBinders.Binders.Add
方法註冊綁定類型.
如下面程式碼.
1 | ModelBinders.Binders.Add(typeof(Arg),new FooModelBinder()); |
ModelBinderDictionary
一般參數透過DefaultModelBinder
來幫我們完成參數綁定.
但有些特別的資料需要透過ModelBinderDictionary
取得使用ModelBinder
,例如上傳檔案,我們可以使用HttpPostedFileBase
來取得檔案資訊流.
那是因為在ModelBinderDictionary
有註冊一個HttpPostedFileBaseModelBinder
來幫我們做解析.
1 | private static ModelBinderDictionary CreateDefaultBinderDictionary() |
IValueProvider 提供參數填值
IValueProvider
介面有一個重要方法GetValue
會返回ValueProviderResult
物件對於ValueProvider
參數封裝
1 | ValueProviderResult GetValue(string key) |
ValueProvider工廠集合(ValueProviderFactories)
在ControllerBase
類別中有一個屬性ValueProvider
設定參數填值動作
1 | public IValueProvider ValueProvider |
Http傳送參數可能又多種模式(Post Form
,Query String
,Ajax
….)
1 | public static class ValueProviderFactories |
ChildActionValueProviderFactory
:取得另一個呼叫`@Html.Action`傳來Model資料FormValueProviderFactory
:取得HTTP POST
送來的資料JsonValueProviderFactory
:取得JSON
資料(Content-Type = application/json
)RouteDataValueProviderFactory
:取得從網址路徑取得到路由參數值QueryStringValueProviderFactory
:取得從Http
請求的Query String
資料HttpFileCollectionValueProviderFactory
:取得檔案上傳功能傳來檔案
如果此次請求匹配到多個ValueProvider
機制會怎處理?
會按照上面
ProviderFactory
設定順序來排執行優先順序來填值
ValueProviderFactory
MVC利用工廠模式透過ValueProviderFactory
實現的工廠來IValueProvider
填值提供者物件.
JsonValueProviderFactory
在ValueProviderFactory
IValueProvider GetValueProvider
1 | public sealed class JsonValueProviderFactory : ValueProviderFactory |
取得IValueProvider
透過ValueProviderFactory
返回相對應的IValueProvider
物件.
下面介紹幾個實現ValueProvider
物件
NameValueCollectionValueProvider
NameValueCollectionValueProvider
可從NameValueCollection
集合取得參數.
因為Request.Form
和Request.QueryString
都是NameValueCollection
類型集合.
這個方法很巧妙利用一個共同參數類型簽章來達成多態轉折點
1 | public virtual NameValueCollection Form |
Http傳值到Server有許多方式,這裡介紹MVC利用哪個ValueProvider將Form
跟QueryString
填值到物件上,很巧妙使用NameValueCollectionValueProvider
建構子參數NameValueCollection
決定是要使用Form
或QueryString
填充值到參數.
1 | public sealed class FormValueProvider : NameValueCollectionValueProvider |
實現IValueProvider
物件主要會依靠GetValue
方法取得ValueProviderResult
.
1 | [ ] |
ValueProviderResult
對於ValueProvider
物件做封裝,一般存放Http
參數擁有兩個只讀屬性
RawValue
表示物件值AttemptedValue
主要用於顯示
ValueProviderResult
提供兩個ConvertTo
重載方法實現向指定目標類型轉換。
某些類型格式化依賴於相應的語言文化(比如時間、日期和貨幣等),這個語言文化通過Culture
屬性來達成.
最終會呼叫一個UnwrapPossibleArrayType
方法來建立物件
小結:
在ControllerActionInvoker.GetParameterValue
取得參數方法,ModelBing
動作有兩個重要的屬性
IValueProvider
:提供如何填值IModelBinder
:建立物件(綁定關聯) 預設使用DefaultModelBinder
類別.
目前分享的IValueProvider
和IModelBinder
UML類別關聯圖如下
下篇會介紹ModelBind
模型綁定重點邏輯,有分簡單參數綁定和複雜參數綁定
BindComplexModel
BindSimpleModel
此文作者:Daniel Shih(石頭)
此文地址: https://isdaniel.github.io/ithelp-day18/
版權聲明:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!