Asp.net web Api源码分析-HttpParameterBinding
接著上文Asp.net web Api源碼分析-Filter 我們提到filter的獲取和調(diào)用,后面通過HttpActionBinding actionBinding = actionDescriptor.ActionBinding;來獲取HttpActionBinding實(shí)例,然后調(diào)用 HttpActionBinding的ExecuteBindingAsync方法來綁定Action參數(shù)。HttpActionDescriptor中 定義了ActionBinding屬性,默認(rèn)的實(shí)現(xiàn)代碼:
?ServicesContainer controllerServices = _controllerDescriptor.Configuration.Services;
?IActionValueBinder actionValueBinder = controllerServices.GetActionValueBinder();
?HttpActionBinding actionBinding = actionValueBinder.GetBinding(this);
這里的actionValueBinder默認(rèn)就是一個(gè)DefaultActionValueBinder實(shí)例,然后調(diào)用它的GetBinding方法。然我們看看DefaultActionValueBinder的GetBinding方法:
? public virtual HttpActionBinding GetBinding(HttpActionDescriptor actionDescriptor)
??????? {
??????????? if (actionDescriptor == null)
??????????? {
??????????????? throw Error.ArgumentNull("actionDescriptor");
??????????? }
??????????? HttpParameterDescriptor[] parameters = actionDescriptor.GetParameters().ToArray();
??????????? HttpParameterBinding[] binders = Array.ConvertAll(parameters, GetParameterBinding);
??????????? HttpActionBinding actionBinding = new HttpActionBinding(actionDescriptor, binders);
??????????? EnsureOneBodyParameter(actionBinding);
??????????? return actionBinding;
??????? }
這里首先獲取當(dāng)前HttpActionDescriptor的參數(shù)集合ReflectedHttpParameterDescriptor[],然后依次調(diào)用GetParameterBinding方法把當(dāng)前HttpActionDescriptor轉(zhuǎn)化為HttpParameterBinding,GetParameterBinding方法如下:
protected virtual HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter){// Attribute has the highest precedence// Presence of a model binder attribute overrides.ParameterBindingAttribute attr = parameter.ParameterBinderAttribute;if (attr != null){return attr.GetBinding(parameter);}// No attribute, so lookup in global map.ParameterBindingRulesCollection pb = parameter.Configuration.ParameterBindingRules;if (pb != null){HttpParameterBinding binding = pb.LookupBinding(parameter);if (binding != null){return binding;}}// Not explicitly specified in global map or attribute.// Use a default policy to determine it. These are catch-all policies. Type type = parameter.ParameterType;if (TypeHelper.IsSimpleUnderlyingType(type) || TypeHelper.HasStringConverter(type)){// For simple types, the default is to look in URI. Exactly as if the parameter had a [FromUri] attribute.return parameter.BindWithAttribute(new FromUriAttribute());}// Fallback. Must be a complex type. Default is to look in body. Exactly as if this type had a [FromBody] attribute.attr = new FromBodyAttribute();return attr.GetBinding(parameter);}?這里我們首先調(diào)用?ParameterBindingAttribute attr = parameter.ParameterBinderAttribute;來獲取ParameterBindingAttribute實(shí)例,然后調(diào)用它的 GetBinding方法來獲取HttpParameterBinding,我們還是來看看ParameterBinderAttribute是如何定義 了吧:
在HttpParameterDescriptor中的ParameterBinderAttribute屬性定義如下:
?public virtual ParameterBindingAttribute ParameterBinderAttribute
??????? {
??????????? get
??????????? {
??????????????? if (_parameterBindingAttribute == null)
??????????????? {
??????????????????? if (!_searchedModelBinderAttribute)
??????????????????? {
??????????????????????? _searchedModelBinderAttribute = true;
??????????????????????? _parameterBindingAttribute = FindParameterBindingAttribute();
??????????????????? }
??????????????? }
??????????????? return _parameterBindingAttribute;
??????????? }
??????????? set { _parameterBindingAttribute = value; }
??????? }
FindParameterBindingAttribute其實(shí)就是查找參數(shù)或則參數(shù)類型的ParameterBindingAttribute特性,如果這里取到的ParameterBindingAttribute屬性多余一個(gè)則最后要拋出異常,具體這里就不說了。
回到DefaultActionValueBinder中GetParameterBinding方法,找不到 ParameterBindingAttribute對(duì)象,我們就 parameter.Configuration.ParameterBindingRules來獲取 ParameterBindingRulesCollection實(shí)例,其中 ParameterBindingRules=DefaultActionValueBinder.GetDefaultParameterBinders(), 其中GetDefaultParameterBinders方法實(shí)現(xiàn)如下:
?internal static ParameterBindingRulesCollection GetDefaultParameterBinders()
??????? {
??????????? ParameterBindingRulesCollection pb = new ParameterBindingRulesCollection();
??????????? pb.Add(typeof(CancellationToken), parameter => new CancellationTokenParameterBinding(parameter));
??????????? pb.Add(typeof(HttpRequestMessage), parameter => new HttpRequestParameterBinding(parameter));
??????????? // Warning binder for HttpContent.
??????????? pb.Add(parameter => typeof(HttpContent).IsAssignableFrom(parameter.ParameterType) ?
??????????????????????????????????? parameter.BindAsError(Error.Format(SRResources.ParameterBindingIllegalType, parameter.ParameterType.Name, parameter.ParameterName))
??????????????????????????????????? : null);
??????????? return pb;
??????? }
這里的ParameterBindingRulesCollection實(shí)例有3個(gè)成員,然后調(diào)用 ParameterBindingRulesCollection的LookupBinding方法來獲取HttpParameterBinding實(shí) 例,其中LookupBinding方法如下:
public class ParameterBindingRulesCollection : Collection<Func<HttpParameterDescriptor, HttpParameterBinding>>
{
?? ? private static Func<HttpParameterDescriptor, HttpParameterBinding> TypeCheck(Type type, Func<HttpParameterDescriptor, HttpParameterBinding> func)
??? {
??????? return (param => (param.ParameterType == type) ? func(param) : null);
??? }
?? ?public void Add(Type typeMatch, Func<HttpParameterDescriptor, HttpParameterBinding> funcInner)
??? {
??????? Add(TypeCheck(typeMatch, funcInner));
??? }
?? ?public HttpParameterBinding LookupBinding(HttpParameterDescriptor parameter)
??? {
??????? foreach (Func<HttpParameterDescriptor, HttpParameterBinding> func in this)
??????? {
??????????? HttpParameterBinding binding = func(parameter);
??????????? if (binding != null)
??????????? {
???????????????? return binding;
??????????? }
??????? }
??????? return null;
??? }
}
所以這里默認(rèn)的ParameterBindingRulesCollection3個(gè)成員是不會(huì)返回HttpParameterBinding實(shí)例。
如果參數(shù)類型是一個(gè)簡(jiǎn)單類型,并且該類型可以轉(zhuǎn)化為string類型,然后調(diào)用? return parameter.BindWithAttribute(new FromUriAttribute());返回HttpParameterBinding,BindWithAttribute方法其實(shí)就是調(diào)用ParameterBindingAttribute的GetBinding方法,這里默認(rèn)FromUriAttribute的GetBinding方法,這里FromUriAttribute的繼承數(shù)如下:FromUriAttribute-》ModelBinderAttribute-》ParameterBindingAttribute。這里的
如果綁定的參數(shù)數(shù)據(jù)類型比較特殊,那么這里我們就調(diào)用FromBodyAttribute的GetBinding方法來獲取HttpParameterBinding實(shí)例,這里的FromBodyAttribute繼承樹如下:
FromBodyAttribute-》ParameterBindingAttribute
在這里我們總結(jié)一下這里找HttpParameterBinding的順序,(1)parameter.ParameterBinderAttribute實(shí)際就是找參數(shù)或參數(shù)類型的ParameterBindingAttribute屬性,(2)
?parameter.Configuration.ParameterBindingRules 從全局的ParameterBindingRules中找HttpParameterBinding,(3)如果參數(shù)類型是一個(gè)簡(jiǎn)單類型且可以轉(zhuǎn)化為 string那么我們調(diào)用parameter.BindWithAttribute(new FromUriAttribute()),(4)最后我們調(diào)用FromBodyAttribute的GetBinding方法來獲取 HttpParameterBinding實(shí)例。
現(xiàn)在我們回到DefaultActionValueBinder的GetBinding方法中來,現(xiàn)在我們已經(jīng)獲取到HttpParameterBinding集合,接下里創(chuàng)建一個(gè)HttpActionBinding實(shí)例,最后調(diào)用EnsureOneBodyParameter來檢查HttpActionBinding的ParameterBindings集合是否有2個(gè)都需要讀取form表單,如果是則拋出異常。到這里HttpActionDescriptor的ActionBinding的創(chuàng)建也就很清楚了。
回到ApiController的ExecuteAsync方法中來,這里繼續(xù)調(diào)用HttpActionBinding的ExecuteBindingAsync方法,這里的ExecuteBindingAsync方法實(shí)現(xiàn)如下:
? public virtual Task ExecuteBindingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
??????? {
??????????? if (_parameterBindings.Length == 0)
??????????? {
??????????????? return TaskHelpers.Completed();
??????????? }
??????????? // First, make sure the actionBinding is valid before trying to execute it. This keeps us in a known state in case of errors.
??????????? foreach (HttpParameterBinding parameterBinder in ParameterBindings)
??????????? {
??????????????? if (!parameterBinder.IsValid)
??????????????? {
??????????????????? // Throwing an exception because the webService developer's action signature is bad.
??????????????????? // This exception will be caught and converted into a 500 by the dispatcher
??????????????????? return TaskHelpers.FromError(new InvalidOperationException(parameterBinder.ErrorMessage));
??????????????? }
??????????? }
??????????? if (_metadataProvider == null)
??????????? {
??????????????? HttpConfiguration config = actionContext.ControllerContext.Configuration;
??????????????? _metadataProvider = config.Services.GetModelMetadataProvider();
??????????? }
??????????? // Execute all the binders.
??????????? IEnumerable<Task> tasks = from parameterBinder in ParameterBindings select parameterBinder.ExecuteBindingAsync(_metadataProvider, actionContext, cancellationToken);
??????????? return TaskHelpers.Iterate(tasks, cancellationToken, disposeEnumerator: false);
??????? }
這個(gè)方法邏輯很簡(jiǎn)單,如果ParameterBindings沒有成員則直接返回,如果有則需要依次驗(yàn)證他們的IsValid,然后再依次調(diào)用他們的ExecuteBindingAsync方法,ExecuteBindingAsync方法的具體執(zhí)行我們這里就不多說了。這里我們看看metadataProvider 是個(gè)什么東東吧,???? SetSingle<ModelMetadataProvider>(new DataAnnotationsModelMetadataProvider());這里我們就知道metadataProvider 其實(shí)是一個(gè)DataAnnotationsModelMetadataProvider實(shí)例,其構(gòu)造函數(shù)也沒什么特別的。這里返回的Task的具體實(shí)現(xiàn)我就不多說了,里面用到了一個(gè)TaskCompletionSource類,具體的使用我這里一而不說了。
?
總結(jié)
以上是生活随笔為你收集整理的Asp.net web Api源码分析-HttpParameterBinding的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 做梦梦到自己好多白头发什么意思
- 下一篇: 女人梦到蛇预示着什么周公解梦