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

时间:2022-08-27 00:18:36

目录

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

备注

[Web API] Web API 2 深入系列(7) Model绑定(下)的更多相关文章

  1. &lbrack;Web API&rsqb; Web API 2 深入系列&lpar;6&rpar; Model绑定&lpar;上&rpar;

    目录 解决什么问题 Model元数据解析 复杂类型 ValueProvider ValueProviderFactory 解决什么问题 Model: Action方法上的参数 Model绑定: 对Ac ...

  2. ASP&period;NET Web API - ASP&period;NET MVC 4 系列

           Web API 项目是 Windows 通信接口(Windows Communication Foundation,WCF)团队及其用户激情下的产物,他们想与 HTTP 深度整合.WCF ...

  3. 如何用Baas快速在腾讯云上开发小程序-系列1:搭建API &amp&semi; WEB WebSocket 服务器

    版权声明:本文由贺嘉 原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/221059001487422606 来源:腾云阁 h ...

  4. HTML5权威指南--Web Storage&comma;本地数据库&comma;本地缓存API&comma;Web Sockets API&comma;Geolocation API&lpar;简要学习笔记二&rpar;

    1.Web Storage HTML5除了Canvas元素之外,还有一个非常重要的功能那就是客户端本地保存数据的Web Storage功能. 以前都是用cookies保存用户名等简单信息.   但是c ...

  5. 初试ASP&period;NET Web API&sol;MVC API(附Demo)

    写在前面 HTTP RESTful 创建Web API 调用Web API 运行截图及Demo下载 ASP.NET Web API是​​一个框架,可以很容易构建达成了广泛的HTTP服务客户端,包括浏览 ...

  6. 我所理解的RESTful Web API &lbrack;Web标准篇&rsqb;

    REST不是一个标准,而是一种软件应用架构风格.基于SOAP的Web服务采用RPC架构,如果说RPC是一种面向操作的架构风格,而REST则是一种面向资源的架构风格.REST是目前业界更为推崇的构建新一 ...

  7. 重构Web Api程序&lpar;Api Controller和Entity&rpar;续篇

    昨天有写总结<重构Web Api程序(Api Controller和Entity)>http://www.cnblogs.com/insus/p/4350111.html,把一些数据交换的 ...

  8. web api写api接口时返回

    web api写api接口时默认返回的是把你的对象序列化后以XML形式返回,那么怎样才能让其返回为json呢,下面就介绍两种方法: 方法一:(改配置法) 找到Global.asax文件,在Applic ...

  9. Google Maps API Web Services

    原文:Google Maps API Web Services 摘自:https://developers.google.com/maps/documentation/webservices/ Goo ...

随机推荐

  1. ApacheCommons的Java公共类库(实现如Log这些功能)

    Apache Commons是Apache软件基金会的项目,曾隶属于Jakarta项目.Commons的目的是提供可重用的.开源的Java代码. 解释:http://baike.baidu.com/i ...

  2. ACdream 1429 Rectangular Polygon

    Rectangular Polygon Time Limit: 1000MS   Memory Limit: 256000KB   64bit IO Format: %lld & %llu D ...

  3. &lbrack;HTML&rsqb;HTML5实现可编辑表格

    HTML5实现的简单的可编辑表格 [HTML]代码 <!DOCTYPE html > <html > <head> <meta charset="u ...

  4. middlewares in GCC

    Our GCC is a project developed by React that makes it painless to create interactive UIs. Design sim ...

  5. 使用translate将字符串中的数字提取出来

    --方法1: with tmp as ( select '按时的撒旦123元(其中含存款11元)' name from dual union all select '一类似的预存9600元(新*)' ...

  6. mysql 5&period;7~默认sql&lowbar;mode解读

    当5.6升级到5.7时,首先要注意的就是sql_mode对业务的影响 大概可以分为几类1 共同支持,如果你的5.6和5.7sql_mode配置支持的交集一样,那么不用考虑2 5.7细说  1 ONLY ...

  7. BZOJ3899 仙人掌树的同构(圆方树&plus;哈希)

    考虑建出圆方树.显然只有同一个点相连的某些子树同构会产生贡献.以重心为根后(若有两个任取一个即可),就只需要处理子树内部了. 如果子树的根是圆点,其相连的同构子树可以任意交换,方案数乘上同构子树数量的 ...

  8. lch 儿童围棋课堂 启蒙篇 &lpar;李昌镐 著&rpar;

    第1章 了解围棋 第2章 无气不活 棋子的"气"第3章 有目数才能赢空第4章 常用术语第5章 吃子第6章 死活:眼第7章 死活:典型棋形第8章 布局:术语篇 第1章 了解围棋 (已 ...

  9. Django 连接redis方法

    1. 按照redis模块 # 在cmd中 pip3 install redis 2. 测试代码 插入单挑数据 import redis conn = redis.Redis(host='10.0.0. ...

  10. memsql 6&period;7集群安装

    预备环境处理 安装yum 源 yum install -y yum-utils yum-config-manager --add-repo https://release.memsql.com/pro ...