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);
}
}
参数分离。