ParameterBindingAttribute
在上一篇中重点讲了ModelBinderAttribute的使用场景。这一篇详细的讲一下ModelBinder背后的参数绑定原理。
ModelBinderAttribute继承自ParameterBindingAttribute,从命名上就是可以看出ParameterBindingAttribute是对Action参数进行绑定的一种特性。除了ModelBinderAttribute之外,WebAPI还另外定义了ValueProviderAttribute,FromUriAttribute与FromBodyAttribute三个ParameterBindingAttribute派生类。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] public abstract class ParameterBindingAttribute : Attribute { protected ParameterBindingAttribute(); public abstract HttpParameterBinding GetBinding(HttpParameterDescriptor parameter); }
ParameterBindingAttribute只提供了一个GetBinding方法,这个方法返回一个HttpParameterBinding类型对象,HttpParameterBinding是参数绑定过程中的一个核心类,它基本完成了从请求数据读取到参数绑定的整个过程。
在这里需要重点关注一下HttpParameterDescriptor,它做作为对参数的一个描述对象,包含了参数的一个信息(这个参后续还将详细讲解)
HttpParameterBinding
public abstract class HttpParameterBinding { protected HttpParameterBinding(HttpParameterDescriptor descriptor); public HttpParameterDescriptor Descriptor { get; } public virtual string ErrorMessage { get; } public bool IsValid { get; } public virtual bool WillReadBody { get; } public abstract Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken); protected object GetValue(HttpActionContext actionContext); protected void SetValue(HttpActionContext actionContext, object value); }
其中ExecuteBindingAsync方法实现具体的参数绑定。对于来自Uri与Body的数据可通过WillReadBody进行区分,WillReadBody默认为false。
ModelBinderParameterBinding
现在我们回过头去再看上一篇的Model绑定。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] public class ModelBinderAttribute : ParameterBindingAttribute { public ModelBinderAttribute(); public ModelBinderAttribute(Type binderType); public Type BinderType { get; set; } public string Name { get; set; } public bool SuppressPrefixCheck { get; set; } public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter); public IModelBinder GetModelBinder(HttpConfiguration configuration, Type modelType); public ModelBinderProvider GetModelBinderProvider(HttpConfiguration configuration); public virtual IEnumerable<System.Web.Http.ValueProviders.ValueProviderFactory> GetValueProviderFactories(HttpConfiguration configuration); }
在ModelBinderParameterBinding中定义了一个GetModelBinderProvider方法。ModelBinderProvider中定义一个GetBinder方法用于获取ModelBinder。
而ModelBinder正是完成Model绑定的基础类。
ModelBinderAttribute
FromUriAttribute
ValueProviderAttribute
FormatterParameterBinding
对于Body中的数据,WebAPI提供了FormatterParameterBinding进行数据绑定。由于Body可以提供的数据格式不像Uri那样单一,所以我们Body能够更加方便的为我们提供复杂的数据结构。FormatterParameterBinding从命名就可以看出来它提供将Body数据反序列化并绑定到参数的功能。
MediaTypeFormatter
对于不同的请求数据格式,FormatterParameter会根据请求的Conent-Type,提供不同的序列化对象。而这些序列化处理类型都继承于MediaTypeFormatter。
下面我列举一下Content-Type与MediaTypeFormatter的对应关系。
Content-Type |
MediaTypeFormatter |
text/xml,application/xml |
XmlMediaTypeFormatter |
text/json,application/json |
MediaTypeFormatter |
application/x-www-form-urlencoded |
FormUrlEncodedMediaTypeFormatter |
application/x-www-form-urlencoded |
JqueryMvcFormUrlEncodedFormatter |
FromBodyAttribute
IActionValueBinder
public interface IActionValueBinder { HttpActionBinding GetBinding(HttpActionDescriptor actionDescriptor); }
绑定入口。
HttpActionBinding
public class HttpActionBinding { public HttpActionBinding(); public HttpActionBinding(HttpActionDescriptor actionDescriptor, HttpParameterBinding[] bindings); public HttpActionDescriptor ActionDescriptor { get; set; } public virtual Task ExecuteBindingAsync(HttpActionContext actionContext, CancellationToken cancellationToken); } }
参数分离。