前面的幾個篇幅把Model部分的知識點劃分成一個個的子產品來講解,而在控制器執行過程中分為好多個過程,對于控制器執行過程(一)主要講解了過濾器以及在後面的過濾器篇幅中也有講到,而在過濾器之中還有一些執行過程,也就是在授權過濾器執行完畢後,行為過濾器執行之前,我們要做的就是Model綁定,面前也都說了之前對Model的知識點子產品都講解的差不多了,今天這個篇幅我們就來看一下這些零散知識點的源頭,也就是Model綁定的入口點。
Model-ActionBinding
HttpActionBinding的由來
我們通過前面幾篇的了解都知道在ASP.NET Web API架構中進入整個Model綁定的入口點就是在HttpActionBinding類型中,對于這個類型前面的篇幅也介紹過,它裡面封裝了ParameterBinding數組,這些ParameterBinding就是控制器方法中每個參數執行Model綁定的對象了,既然我們知道HttpActionBinding類型中有着許多ParameterBinding類型的對象執行個體,那麼我們就要看看HttpActionBinding類型是怎麼生成的。
示例代碼1-1
1
<code>this</code><code>.SetSingle<IActionValueBinder>(</code><code>new</code> <code>DefaultActionValueBinder());</code>
首先我們看到示例代碼1-1中可以看到在HttpConfiguration類型的服務容器中,預設注冊為IActionValueBinder類型服務的是DefaultActionValueBinder類型。
示例代碼1-2
2
3
4
5
6
7
8
9
10
<code>namespace</code> <code>System.Web.Http.ModelBinding</code>
<code>{</code>
<code> </code><code>public</code> <code>class</code> <code>DefaultActionValueBinder : IActionValueBinder</code>
<code> </code><code>{</code>
<code> </code><code>public</code> <code>DefaultActionValueBinder();</code>
<code> </code><code>public</code> <code>virtual</code> <code>HttpActionBinding GetBinding(HttpActionDescriptor actionDescriptor);</code>
<code> </code><code>protected</code> <code>virtual</code> <code>HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter);</code>
<code> </code><code>}</code>
<code>}</code>
代碼1-2中所示的是DefaultActionValueBinder類型的定義,其中的這兩個方法很重要,第一個GetBinding()方法是用以架構内部來進行調用,根據HttpActionDescriptor控制器方法描述類型對象擷取到我們所需的HttpActionBinding,而其内部實作則是調用下面的GetParameterBinding()方法,利用HttpActionDescriptor對象擷取到HttpParameterDescriptor集合後,然後周遊的去調用GetParameterBinding()方法,進而能夠擷取到HttpParameterBinding對象執行個體,最後生成HttpActionBinding對象執行個體,從設計角度來看這個DefaultActionValueBinder類型中的兩個方法GetBinding()和GetParameterBinding()方法都是采用了templatemethod模式,這種模式在架構設計中很常見。
HttpParameterBinding的由來
下面我們就要來說說GetParameterBinding()方法的細節實作了因為關乎着使用哪種方式來進行綁定。也就是根據HttpParameterDescriptor類型執行個體怎麼去建立HttpParameterBinding的。
示例代碼1-3
11
12
13
14
15
16
17
18
19
20
21
22
23
<code> </code><code>protected</code> <code>virtual</code> <code>HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter)</code>
<code> </code><code>ParameterBindingAttribute parameterBinderAttribute = parameter.ParameterBinderAttribute;</code>
<code> </code><code>if</code> <code>(parameterBinderAttribute == </code><code>null</code><code>)</code>
<code> </code><code>{</code>
<code> </code><code>ParameterBindingRulesCollection parameterBindingRules = parameter.Configuration.ParameterBindingRules;</code>
<code> </code><code>if</code> <code>(parameterBindingRules != </code><code>null</code><code>)</code>
<code> </code><code>{</code>
<code> </code><code>HttpParameterBinding binding = parameterBindingRules.LookupBinding(parameter);</code>
<code> </code><code>if</code> <code>(binding != </code><code>null</code><code>)</code>
<code> </code><code>{</code>
<code> </code><code>return</code> <code>binding;</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>Type parameterType = parameter.ParameterType;</code>
<code> </code><code>if</code> <code>(TypeHelper.IsSimpleUnderlyingType(parameterType) || TypeHelper.HasStringConverter(parameterType))</code>
<code> </code><code>return</code> <code>parameter.BindWithAttribute(</code><code>new</code> <code>FromUriAttribute());</code>
<code> </code><code>parameterBinderAttribute = </code><code>new</code> <code>FromBodyAttribute();</code>
<code> </code><code>}</code>
<code> </code><code>return</code> <code>parameterBinderAttribute.GetBinding(parameter);</code>
<code> </code><code>}</code>
代碼1-3就是具體的實作了,那我們就就來看一下其中的過程以及會涉及到的類型。
首先會根據參數HttpParameterDescriptor類型執行個體擷取到在這個控制器方法參數上使用了ParameterBindingAttribute辨別,并且擷取ParameterBindingAttribute類型執行個體。我們暫且就來看一下ParameterBindingAttribute類型定義。
示例代碼1-4
<code> </code><code>[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class, Inherited = </code><code>true</code><code>, AllowMultiple = </code><code>false</code><code>)]</code>
<code> </code><code>public</code> <code>abstract</code> <code>class</code> <code>ParameterBindingAttribute : Attribute</code>
<code> </code><code>// Methods</code>
<code> </code><code>protected</code> <code>ParameterBindingAttribute();</code>
<code> </code><code>public</code> <code>abstract</code> <code>HttpParameterBinding GetBinding(HttpParameterDescriptor parameter);</code>
從代碼1-4可以看出,這個ParameterBindingAttribute類型适用于類型以及參數,也就是說我們選擇綁定的方式可以在Model類型定義的時候辨別這個特性,也可以在定義控制器方法的時候适當的給參數這個特性辨別。
然而在這個類型中為什麼會有GetBinding()方法呢?因為這個類型是抽象類型,也就是采用了上面所說過的template method模式,而在子類實作中,根據自身适應的情況生成響應的HttpParameterBinding類型。看下如下的圖表示相關的對象模型。
圖1
上面圖1中涉及到的每個類型大家可以去看前面的篇幅,篇幅中有遺漏的就麻煩大家自己多動一下手去看看吧。
HttpParameterBinding的選擇機制
接着代碼1-3的思緒,在我們擷取到了ParameterBindingAttribute之後,并不知道這個控制器方法中的參數是否辨別有ParameterBindingAttribute,或者是參數類型上是否有辨別。這個時候假使是有的話,可以看到代碼1-3中的最後一句代碼,直接使用擷取到的ParameterBindingAttribute類型進行調用GetBinding()方法,也就是在上一小節中圖1所示的那樣。
然而還有一種情況,就是我們在定義控制器方法的時候參數沒有明确的辨別我們要使用某種綁定機制,或者是在定義Model的時候沒有明确的表示,這個時候架構則會從定義好的規則集合中根據目前控制其方法參數的描述類型來擷取對應的ParameterBinding類型執行個體。如下的示例代碼定義了規則集合的定義。
示例代碼1-5
<code> </code><code>internal</code> <code>static</code> <code>ParameterBindingRulesCollection GetDefaultParameterBinders()</code>
<code> </code><code>ParameterBindingRulesCollection ruless = </code><code>new</code> <code>ParameterBindingRulesCollection();</code>
<code> </code><code>ruless.Add(</code><code>typeof</code><code>(CancellationToken), parameter => </code><code>new</code> <code>CancellationTokenParameterBinding(parameter));</code>
<code> </code><code>ruless.Add(</code><code>typeof</code><code>(HttpRequestMessage), parameter => </code><code>new</code> <code>HttpRequestParameterBinding(parameter));</code>
<code> </code><code>ruless.Add(</code><code>delegate</code> <code>(HttpParameterDescriptor parameter) {</code>
<code> </code><code>if</code> <code>(!</code><code>typeof</code><code>(HttpContent).IsAssignableFrom(parameter.ParameterType))</code>
<code> </code><code>return</code> <code>null</code><code>;</code>
<code> </code><code>return</code> <code>parameter.BindAsError(Error.Format(SRResources.ParameterBindingIllegalType, </code><code>new</code> <code>object</code><code>[] { parameter.ParameterType.Name, parameter.ParameterName }));</code>
<code> </code><code>});</code>
<code> </code><code>return</code> <code>ruless;</code>
代碼1-5中所表示的就是規則定義,意思就是在我們使用HttpParameterDescriptor類型執行個體來從集合中想擷取ParameterBinding的時候,ParameterBindingRulesCollection類型會把我們的HttpParameterDescriptor類型執行個體中的ParameterType取出來和之前定義的每一項規則的類型進行比對,類型吻合了就會随之調用對應的委托類型進行ParameterBinding生成。從代碼1-5中我們可以看到的是規則中隻有CancellationToken類型和HttpRequestMessage類型,假使這個時候我們的控制其方法參數類型是自定義的複雜類型,這裡也都沒有定義,這個時候架構會取出HttpParameterDescriptor類型中的ParameterType進行判斷,假使是可以轉換成string類型的簡單類型參數,則會生成一個FromUriAttribute類型作為辨別,FromUriAttribute類型繼承自ModelBinderAttribute類型。
假使這裡的判斷沒有通過則說明是複雜類型,最後我們再看待代碼1-3中的定義最後生成的是FromBodyAttribute辨別類型,這個時候請參照圖1。
本文轉自jinyuan0829 51CTO部落格,原文連結:http://blog.51cto.com/jinyuan/1558338,如需轉載請自行聯系原作者