[Web API] Web API 2 深入系列(7) Model绑定(下)

版权声明:此文章转载自_infocool

原文链接:http://www.infocool.net/kb/ASP/201610/205968.html

如需转载请联系听云College团队成员小尹 邮箱:yinhy#tingyun.com

目录

ModelBinder

ModelBinderProvider

不同类型的Model绑定

简单类型

复杂类型

其他类型

ModelBinder

ModelBinder是Model绑定的核心.

public interface IModelBinder
{
    //绑定Model方法,返回绑定是否成功
    bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext);
}
ModelBindingContext
public class ModelBindingContext
{
    //数据源
    public IValueProvider ValueProvider { get; set; }
    //最终创建的对象 绑定过程就是创建Model
    public object Model { get; set; }
    //参数名称
    public string ModelName { get; set; }
    //参数类型
    public Type ModelType { get; }
    //参数元数据
    public ModelMetadata ModelMetadata { get; set; }
    //属性元数据
    public IDictionary<string, ModelMetadata> PropertyMetadata { get; }
    //存储绑定结果(包括错误信息,ValueProviderResult),该值引用自ApiController的ModelState
    public ModelStateDictionary ModelState { get; set; }
    
    public bool FallbackToEmptyPrefix { get; set; }
}

当ModelBinder特性的Name(为null),FallbackToEmptyPrefix为True.

FallbackToEmptyPrefix为False时,则必须数据源有前缀才能绑定上.

Web API定义了一系列的ModelBinder,这里先介绍

public class CompositeModelBinder : IModelBinder
{
    //IModelBinder 集合
    public CompositeModelBinder(params IModelBinder[] binders)
    //使用内部ModelBinder进行绑定Model(默认遍历一次,如果FallbackToEmptyPrefix为True,则会有2次遍历机会)
    public virtual bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
}
ModelBinderProvider
Web API通过ModelBinderProvider创建ModelBinder
public abstract class ModelBinderProvider
{
    public abstract IModelBinder GetBinder(HttpConfiguration configuration, Type modelType);
}

Web API中默认注册了一系列的ModelBinderProvider

    this.SetMultiple<ModelBinderProvider>(new ModelBinderProvider[8]
    {
        (ModelBinderProvider) new TypeConverterModelBinderProvider(),
        (ModelBinderProvider) new TypeMatchModelBinderProvider(),
        (ModelBinderProvider) new KeyValuePairModelBinderProvider(),
        (ModelBinderProvider) new ComplexModelDtoModelBinderProvider(),
        (ModelBinderProvider) new ArrayModelBinderProvider(),
        (ModelBinderProvider) new DictionaryModelBinderProvider(),
        (ModelBinderProvider) new CollectionModelBinderProvider(),
        (ModelBinderProvider) new MutableObjectModelBinderProvider()
    });

对应的我们先介绍一下

//同样都是组装一批ModelBinderProvider
public sealed class CompositeModelBinderProvider : ModelBinderProvider
{
    public CompositeModelBinderProvider(IEnumerable<ModelBinderProvider> providers)
    public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
}
ModelBinderAttribute除了通过Name设置FallbackToEmptyPrefix,还有个更重要的属性BinderType
public class ModelBinderAttribute : ParameterBindingAttribute
{
    public string Name { get; set; }
    //用来指定ModelBinder 或 ModelBinderProvider
    public Type BinderType { get; set; }
}

不同类型的Model绑定

不同的数据类型,有不同的数据结构.

所以针对他们的绑定机制也是不同的.

简单类型

TypeConverterModelBinder

public sealed class TypeConverterModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
        model = valueProviderResult.ConvertTo(bindingContext.ModelType);
        bindingContext.Model = model;
        return true;
    }
}

复杂类型

在介绍复杂类型的Bind前,先介绍一下下面2个类型.

ComplexModelDto包含复杂类型的元数据和绑定结果

public class ComplexModelDto
{
    public ComplexModelDto(ModelMetadata modelMetadata, IEnumerable<ModelMetadata> propertyMetadata)
    public ModelMetadata ModelMetadata { get; private set; }
    public Collection<ModelMetadata> PropertyMetadata { get; private set; }
    //key 为属性的元数据,value 为绑定结果
    public IDictionary<ModelMetadata, ComplexModelDtoResult> Results { get; private set; }
}
ComplexModelDtoResult
public sealed class ComplexModelDtoResult
{
    //绑定结果值
    public object Model { get; private set; }
    //验证信息
    public ModelValidationNode ValidationNode { get; private set; }
}

复杂类型的绑定由 MutableObjectModelBinder 和 ComplexModelDtoModelBinder共同完成.

而上面2个类型,实际就是用来在2个ModelBinder间传递的对象

public class MutableObjectModelBinder : IModelBinder
{
    public virtual bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        //类型筛选
        if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName) || !MutableObjectModelBinder.CanBindType(bindingContext.ModelType))
            return false;
        //1. 创建空对象
        bindingContext.ModelMetadata.Model = Activator.CreateInstance(bindingContext.ModelType);
        //2. 创建ComplexModelDto对象
        ComplexModelDto complexModelDto = new ComplexModelDto(bindingContext.ModelMetadata,bindingContext.PropertyMetadata);
        //3. 进入绑定流程
        this.ProcessDto(actionContext, bindingContext, complexModelDto);
        return true;
    }
    internal void ProcessDto(HttpActionContext actionContext, ModelBindingContext bindingContext, ComplexModelDto dto)
    {
        //创建子ModelBindingContext
        var subContext = new ModelBindingContext(bindingContext)
        {
            ModelName = bindingContext.ModelName,
            ModelMetadata = GetMetadata(typeof(ComplexModelDto))
        };
        //调用ComplexModelDtoModelBinder 对ComplexModelDto进行绑定
        actionContext.Bind(subContext);
        //对复杂类型的属性进行绑定
        foreach (var result in (IEnumerable<KeyValuePair<ModelMetadata, ComplexModelDtoResult>>) dto.Results)
        {
            ModelMetadata key = result.Key;
            ComplexModelDtoResult dtoResult = result.Value;
            if (dtoResult != null)
            {
                var property = bindingContext.ModelType.GetProperty(key.PropertyName);
                this.SetProperty(actionContext, bindingContext, key, dtoResult,property);
            }
        }
    }
}

ComplexModelDtoModelBinder则将所有属性再通过调度其他的ModelBinder进行绑定.并将结果保存在ComplexModelDto的Results属性中.

其他类型

Web API还提供了其他常用的数据类型 ModelBinder

CollectionModelBinder来实现 集合 类型(指的集合是实现了IEnumerable接口的类型)

ArrayModelBinder来实现 数组 类型

DictionaryModelBinder来实现 字典 类型

通过对应的ModelBinderProvider可以知道对应的ModelBinder 能实现哪种类型的绑定

备注

文章中的代码并非完整WebAPI代码,一般是经过自己精简后的.

本篇内容使用MarkDown语法编辑

首发地址:http://neverc.infocool.net/p/6006274.html


想阅读更多技术文章,请访问听云技术博客,访问听云官方网站感受更多应用性能优化魔力。

关于作者

coco秋洁

我爱学习,学习使我快乐

我要评论

评论请先登录,或注册