zoukankan      html  css  js  c++  java
  • [Web API] Web API 2 深入系列(7) Model绑定(下)

    目录

    1. ModelBinder

    2. ModelBinderProvider

    3. 不同类型的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 能实现哪种类型的绑定

    备注

  • 相关阅读:
    JAVA 8的新特性
    JAVA中map的分类和各自的特性
    设计模式之工厂方法模式(附实例代码下载)
    为什么重写equals还要重写hashcode??
    C# static的用法详解
    1-RadioButton控件的用法
    C#三种常用的读取XML文件的方法
    VS2017 中安装SVN
    pip安装selenium时,报错“You are using pip version 10.0.1, however version 18.0 is available.”的问题
    问题:unknown error: call function result missing 'value' 解决方法
  • 原文地址:https://www.cnblogs.com/neverc/p/6006274.html
Copyright © 2011-2022 走看看