前面的幾個篇幅把Model部分的知識點劃分紅一個個的模塊來說解,而在控制器執行過程當中分爲好多個過程,對於控制器執行過程(一)主要講解了過濾器以及在後面的過濾器篇幅中也有講到,而在過濾器之中還有一些執行過程,也就是在受權過濾器執行完畢後,行爲過濾器執行以前,咱們要作的就是Model綁定,面前也都說了以前對Model的知識點模塊都講解的差很少了,今天這個篇幅咱們就來看一下這些零散知識點的源頭,也就是Model綁定的入口點。數組
HttpActionBinding的由來框架
咱們經過前面幾篇的瞭解都知道在ASP.NET Web API框架中進入整個Model綁定的入口點就是在HttpActionBinding類型中,對於這個類型前面的篇幅也介紹過,它裏面封裝了ParameterBinding數組,這些ParameterBinding就是控制器方法中每一個參數執行Model綁定的對象了,既然咱們知道HttpActionBinding類型中有着許多ParameterBinding類型的對象實例,那麼咱們就要看看HttpActionBinding類型是怎麼生成的。less
示例代碼1-1this
this.SetSingle<IActionValueBinder>(new DefaultActionValueBinder());
首先咱們看到示例代碼1-1中能夠看到在HttpConfiguration類型的服務容器中,默認註冊爲IActionValueBinder類型服務的是DefaultActionValueBinder類型。spa
示例代碼1-2設計
namespace System.Web.Http.ModelBinding { public class DefaultActionValueBinder : IActionValueBinder { public DefaultActionValueBinder(); public virtual HttpActionBinding GetBinding(HttpActionDescriptor actionDescriptor); protected virtual HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter); } }
代碼1-2中所示的是DefaultActionValueBinder類型的定義,其中的這兩個方法很重要,第一個GetBinding()方法是用以框架內部來進行調用,根據HttpActionDescriptor控制器方法描述類型對象獲取到咱們所需的HttpActionBinding,而其內部實現則是調用下面的GetParameterBinding()方法,利用HttpActionDescriptor對象獲取到HttpParameterDescriptor集合後,而後遍歷的去調用GetParameterBinding()方法,從而可以獲取到HttpParameterBinding對象實例,最後生成HttpActionBinding對象實例,從設計角度來看這個DefaultActionValueBinder類型中的兩個方法GetBinding()和GetParameterBinding()方法都是採用了template method模式,這種模式在框架設計中很常見。3d
HttpParameterBinding的由來code
下面咱們就要來講說GetParameterBinding()方法的細節實現了由於關乎着使用哪一種方式來進行綁定。也就是根據HttpParameterDescriptor類型實例怎麼去建立HttpParameterBinding的。orm
示例代碼1-3對象
protected virtual HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter) { ParameterBindingAttribute parameterBinderAttribute = parameter.ParameterBinderAttribute; if (parameterBinderAttribute == null) { ParameterBindingRulesCollection parameterBindingRules = parameter.Configuration.ParameterBindingRules; if (parameterBindingRules != null) { HttpParameterBinding binding = parameterBindingRules.LookupBinding(parameter); if (binding != null) { return binding; } } Type parameterType = parameter.ParameterType; if (TypeHelper.IsSimpleUnderlyingType(parameterType) || TypeHelper.HasStringConverter(parameterType)) { return parameter.BindWithAttribute(new FromUriAttribute()); } parameterBinderAttribute = new FromBodyAttribute(); } return parameterBinderAttribute.GetBinding(parameter); }
代碼1-3就是具體的實現了,那咱們就就來看一下其中的過程以及會涉及到的類型。
首先會根據參數HttpParameterDescriptor類型實例獲取到在這個控制器方法參數上使用了ParameterBindingAttribute標識,而且獲取ParameterBindingAttribute類型實例。咱們暫且就來看一下ParameterBindingAttribute類型定義。
示例代碼1-4
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] public abstract class ParameterBindingAttribute : Attribute { // Methods protected ParameterBindingAttribute(); public abstract HttpParameterBinding GetBinding(HttpParameterDescriptor parameter); }
從代碼1-4能夠看出,這個ParameterBindingAttribute類型適用於類型以及參數,也就是說咱們選擇綁定的方式能夠在Model類型定義的時候標識這個特性,也能夠在定義控制器方法的時候適當的給參數這個特性標識。
然而在這個類型中爲何會有GetBinding()方法呢?由於這個類型是抽象類型,也就是採用了上面所說過的template method模式,而在子類實現中,根據自身適應的狀況生成響應的HttpParameterBinding類型。看下以下的圖表示相關的對象模型。
圖1
上面圖1中涉及到的每一個類型你們能夠去看前面的篇幅,篇幅中有遺漏的就麻煩你們本身多動一下手去看看吧。
HttpParameterBinding的選擇機制
接着代碼1-3的思緒,在咱們獲取到了ParameterBindingAttribute以後,並不知道這個控制器方法中的參數是否標識有ParameterBindingAttribute,或者是參數類型上是否有標識。這個時候假使是有的話,能夠看到代碼1-3中的最後一句代碼,直接使用獲取到的ParameterBindingAttribute類型進行調用GetBinding()方法,也就是在上一小節中圖1所示的那樣。
然而還有一種狀況,就是咱們在定義控制器方法的時候參數沒有明確的標識咱們要使用某種綁定機制,或者是在定義Model的時候沒有明確的表示,這個時候框架則會從定義好的規則集合中根據當前控制其方法參數的描述類型來獲取對應的ParameterBinding類型實例。以下的示例代碼定義了規則集合的定義。
示例代碼1-5
internal static ParameterBindingRulesCollection GetDefaultParameterBinders() { ParameterBindingRulesCollection ruless = new ParameterBindingRulesCollection(); ruless.Add(typeof(CancellationToken), parameter => new CancellationTokenParameterBinding(parameter)); ruless.Add(typeof(HttpRequestMessage), parameter => new HttpRequestParameterBinding(parameter)); ruless.Add(delegate (HttpParameterDescriptor parameter) { if (!typeof(HttpContent).IsAssignableFrom(parameter.ParameterType)) { return null; } return parameter.BindAsError(Error.Format(SRResources.ParameterBindingIllegalType, new object[] { parameter.ParameterType.Name, parameter.ParameterName })); }); return ruless; }
代碼1-5中所表示的就是規則定義,意思就是在咱們使用HttpParameterDescriptor類型實例來從集合中想獲取ParameterBinding的時候,ParameterBindingRulesCollection類型會把咱們的HttpParameterDescriptor類型實例中的ParameterType取出來和以前定義的每一項規則的類型進行比對,類型吻合了就會隨之調用對應的委託類型進行ParameterBinding生成。從代碼1-5中咱們能夠看到的是規則中只有CancellationToken類型和HttpRequestMessage類型,假使這個時候咱們的控制其方法參數類型是自定義的複雜類型,這裏也都沒有定義,這個時候框架會取出HttpParameterDescriptor類型中的ParameterType進行判斷,假使是能夠轉換成string類型的簡單類型參數,則會生成一個FromUriAttribute類型做爲標識,FromUriAttribute類型繼承自ModelBinderAttribute類型。
假使這裏的判斷沒有經過則說明是複雜類型,最後咱們再看待代碼1-3中的定義最後生成的是FromBodyAttribute標識類型,這個時候請參照圖1。
做者:金源
出處:http://www.cnblogs.com/jin-yuan/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面