ASP.NET Web API Model-ParameterBinding

简介:

ASP.NET Web API Model-ParameterBinding

前言

通过上个篇幅的学习了解Model绑定的基础知识,然而在ASP.NET Web APIModel绑定功能模块并不是被直接调用的,而是要通过本篇要介绍的内容ParameterBinding的一系列对象对其进行封装调用,通过本篇的学习之后也会大概的清楚在Web API中绑定会有哪几种方式。

 

Model-ParameterBinding(对象篇)

ASP.NET Web APIParameterBinding代表着参数绑定并且在这其中涉及了几种绑定的方式,然而ParaMeterBinding并不是单独执行的,就好比一个控制器方法中有可能会有多个参数一样,所以我们就先来看一下ActionBinding的相关对象,对于这些对象的生成的环境以及过程我们在后面的篇幅中会有讲解。

 

HttpActionBinding

代码1-1

1
2
3
4
5
6
7
8
9
10
11
12
namespace  System.Web.Http.Controllers
{
     public  class  HttpActionBinding
     {
         public  HttpActionBinding();
         public  HttpActionBinding(HttpActionDescriptor actionDescriptor, HttpParameterBinding[] bindings);
         public  HttpActionDescriptor ActionDescriptor {  get set ; }
         public  HttpParameterBinding[] ParameterBindings {  get set ; }
 
         public  virtual  Task ExecuteBindingAsync(HttpActionContext actionContext, CancellationToken cancellationToken);
     }
}

代码1-1中对于HttpActionBinding类型的定义一目了然,看HttpActionBinding类型的重载构造函数中有HttpActionDescriptor类型、HttpParameterBinding类型的数组类型作为参数,HttpActionDescriptor类型作为控制器方法描述类型大家已经很熟悉了吧,这个类型中包含着控制器方法的元数据信息,而后者HttpParameterBinding类型则是表示着参数绑定对象,其实在Model绑定中每个参数的绑定都是通过ParameterBinding来绑定的,所以这里的执行过程我们暂时不去深入了解,就是单纯的了解一下相关的对象模型。

 

HttpParameterBinding

代码1-2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace  System.Web.Http.Controllers
{
     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);
     }
}

在代码1-2中我们看到HttpParameterBinding类型的定义,可以看到HttpParameterBinding是抽象类型,并且实现绑定的方法ExecuteBindingAsync()也是抽象的,这也是为了在不同的环境和情况相爱采取不同的绑定机制做好铺垫就是多态啦,这个我们后面会说,我们还是先看下HttpParameterBinding类型的内部定义,首先我们看到的是构造函数中的参数类型,HttpParameterDescriptor类型,又是一个对象描述类型,这次的描述对象则是控制其方法中的某个参数,而HttpParameterBinding对象实例的生成则是根据HttpParameterDescriptor对象实例而来,这个后续的篇幅中会有讲解。ErrorMessage属性表示在ParameterBinding绑定的过程中出现的错误信息,而IsValid属性表示绑定是否可以完成的依据就是判断ErrorMessage属性是否为NullWillReadBody属性表示ParameterBinding对象是否读取Http消息正文内容作为参数绑定的数据源,这个稍后给大家看的示例中就有,一看便知。GetValue()SetValue()方法就是向当前HttpActionContext中获取对应的参数值和设置参数对应值。

 

 

ModelBinderParameterBinding

代码1-3

1
2
3
4
5
6
7
8
9
10
11
12
namespace  System.Web.Http.ModelBinding
{
     public  class  ModelBinderParameterBinding : HttpParameterBinding, IValueProviderParameterBinding
     {
         public  ModelBinderParameterBinding(HttpParameterDescriptor descriptor, IModelBinder modelBinder, IEnumerable<System.Web.Http.ValueProviders.ValueProviderFactory> valueProviderFactories);
 
         public  IModelBinder Binder {  get ; }
         public  IEnumerable<System.Web.Http.ValueProviders.ValueProviderFactory> ValueProviderFactories {  get ; }
 
         public  override  Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken);
     }
}

代码1-3表示的是ModelBinderParameterBinding类型,这个类型代表的绑定方式(绑定的数据来源)是通过IModelBinder来获取的,也就正如代码1-3中我们看到的构造函数一样,其中有IModelBinderValueProviderFactory类型的集合,这些就是数据绑定的数据源。Binder属性和ValueProviderFactories属性也就是构造函数传入的两个类型值。对于绑定的细节这里就不说多了。

 

FormatterParameterBinding

代码1-4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
namespace  System.Web.Http.ModelBinding
{
     public  class  FormatterParameterBinding : HttpParameterBinding
     {
         public  FormatterParameterBinding(HttpParameterDescriptor descriptor, IEnumerable<MediaTypeFormatter> formatters, IBodyModelValidator bodyModelValidator);
 
         public  IBodyModelValidator BodyModelValidator {  get set ; }
         public  override  string  ErrorMessage {  get ; }
         public  IEnumerable<MediaTypeFormatter> Formatters {  get set ; }
         public  override  bool  WillReadBody {  get ; }
 
         public  override  Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken);
         public  virtual  Task< object > ReadContentAsync(HttpRequestMessage request, Type type, IEnumerable<MediaTypeFormatter> formatters, IFormatterLogger formatterLogger);
     }
}

代码1-4中所示的FormatterParameterBinding类型是通过哪种方式来获取绑定数据源的呢?大家可以看到WillReadBody属性在这个类型中被重写了,原来在HttpParameterBinding类型中默认为false的是不会对Http请求的正文内容进行读写的,而这里在FormatterParameterBinding类型中,已然的重写了,说明在这个类型中我们所能用到的绑定数据源就是从Http请求的正文内容来读取了,然而Http请求的正文内容并不是直接放在那里供我们读取的,而是在客户端发送前就已经被指定的序列化器序列化了。

那么我们在服务器端就要反序列化才能获取到值,这里在代码1-4中我们看到构造函数中可以看到和代码1-3一样都是具有一个HttpParameterDescriptor类型的参数对象,而后则是一个MediaTypeFormatter类型的集合对象,最后是进行Model验证的对象,这个后续再说。

现在我们就来看看第二个参数类型中的MediaTypeFormatter类型。

 

MediaTypeFormatter

代码1-5

1
2
3
4
5
6
7
8
9
10
11
namespace  System.Net.Http.Formatting
{
     public  abstract  class  MediaTypeFormatter
     {
         protected  MediaTypeFormatter();
         public  abstract  bool  CanReadType(Type type);
         public  abstract  bool  CanWriteType(Type type);
         public  virtual  Task< object > ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger);
         public  virtual  Task WriteToStreamAsync(Type type,  object  value, Stream writeStream, HttpContent content, TransportContext transportContext);
     }
}

在代码1-5中所示的MediaTypeFormatter类型是被删减过的一部分,所剩4个方法中两个是抽象方法两个是虚方法,先看两个抽象方法的定义,CanReadType()方法表示的是根据指定的参数类型从当前的Http请求正文中能否读取到改类型的值,简单来说就是能否把正文内容反序列化为指定的参数类型,同理CanWriterType()是对响应正文进行操作判断。而ReadFromStreamAsync()方法和WriteToStreamAsync()方法则是对Http请求正文内容和Http响应正文内容进行实际操作的两个方法。

 

对于MediaTypeFormatter类型的实现类型比如说针对Json格式的JsonMediaTypeFormatter和针对Xml格式的XmlMediaTypeFormatter.

 

我们看一下JsonMediaTypeFormatter类型的简单示例,大家就会知道是怎么回事了。

首先我们在服务器端的控制器中定义一个接收Post请求的方法,

代码1-6

1
2
3
4
5
         [CustomControllerActionAuthorizationFilter]
         public  void  Post(Product product)
         {
             products.Add(product);
         }

为了方便演示在其控制其方法上加了个授权过滤器,然后我们对Post请求的处理使用JsonMediaTypeFormatter类型进行反序列化的操作将在CustomControllerActionAuthorizationFilter过滤器类型中进行。

代码1-7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  Task<System.Net.Http.HttpResponseMessage> ExecuteAuthorizationFilterAsync(System.Web.Http.Controllers.HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken, Func<Task<System.Net.Http.HttpResponseMessage>> continuation)
         {
             Console.WriteLine(actionContext.Request.Content.Headers.ContentType.MediaType);
 
             IEnumerable<MediaTypeFormatter> formatters =  new  MediaTypeFormatter[] 
             {
                 new  JsonMediaTypeFormatter()
             };
             Product product = actionContext.Request.Content.ReadAsAsync<Common.Product>(formatters).Result;
             Console.WriteLine(product.ProductID);
             Console.WriteLine(product.ProductName);
             Console.WriteLine(product.ProductCategory);
             return  continuation();
         }

在代码1-7中,在请求到达控制器方法之前会先经过授权过滤器,在这其中首先我们是先向服务器端的控制器输出了当前请求的格式类型,然后就对当前请求的正文内容使用JsonMediaTypeFormatter类型进行反序列化操作。

我们再看下客户端使用HttpClient类型进行模拟Post请求,

代码1-8

1
2
3
4
5
6
7
8
             HttpClient httpClient =  new  HttpClient();
             Product product =  new  Product()
             {
                 ProductID =  "003" ,
                 ProductName =  "旺仔牛奶" ,
                 ProductCategory =  "食品类"
             };
             await httpClient.PostAsJsonAsync<Product>( "http://localhost/selfhost/api/product" , product);


最后结果如图1.

1

wKiom1QgH5Wi-8LAAACfAIHT_nY932.jpg

看到这里想必大家也知道对于XmlMediaTypeFormatter的使用方式是怎样的了。

还有一种MediaTypeFormatter类型FormUrlEncodedMediaTypeFormatter类型,FormUrlEncodedMediaTypeFormatter类型表示的是在Http Post请求中表单提交的数据所用格式器,我们看一下FormUrlEncodedMediaTypeFormatter类型中CanReadType()方法的实现。

代码1-9

1
2
3
4
5
6
7
8
9
10
11
12
     public  override  bool  CanReadType(Type type)
     {
         if  (type ==  null )
         {
             throw  Error.ArgumentNull( "type" );
         }
         if  (!(type ==  typeof (FormDataCollection)))
         {
             return  FormattingUtilities.IsJTokenType(type);
         }
         return  true ;
     }

在代码1-9我们可以看到FormDataCollection类型实际就是IEnumerable<KeyValuePair<string,string>>类型的对象,在表单提交后的请求Url中大家也都可以看到是是key=value的形式,所以这里就是这种格式的。对于这个格式器的示例会在后面的篇幅给大家做演示讲解。

 

HttpRequestParameterBinding

最后我们再看一个RequestParameterBinding对象。

代码1-10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
     public  class  HttpRequestParameterBinding : HttpParameterBinding
     {
         // Methods
         public  HttpRequestParameterBinding(HttpParameterDescriptor descriptor)
             base (descriptor)
         {
         }
 
         public  override  Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
         {
             string  parameterName =  base .Descriptor.ParameterName;
             HttpRequestMessage request = actionContext.ControllerContext.Request;
             actionContext.ActionArguments.Add(parameterName, request);
             return  TaskHelpers.Completed();
         }
     }

在代码1-10中我们看到再ExecuteBindingAsync()方法的实现中,是直接获取到参数名称和当前的请求对象,然后添加到控制其方法执行上下文的ActionArguments属性中,在之前的篇幅中也说过这个属性用来存放方法对应参数值(Model绑定后的值)。

本篇关于ParameterBinding的对象介绍就到这里,都是零零散散的不过在后面的篇幅中都会有示例介绍说明的。







     本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1557178 ,如需转载请自行联系原作者

相关文章
|
3月前
|
域名解析 缓存 Linux
如何让你的.NET WebAPI程序支持HTTP3?
如何让你的.NET WebAPI程序支持HTTP3?
47 2
如何让你的.NET WebAPI程序支持HTTP3?
|
Linux Docker 容器
.net Core WebApi发布到Docker并推送到阿里云容器服务
.net Core WebApi发布到Docker并推送到阿里云容器服务
604 0
.net Core WebApi发布到Docker并推送到阿里云容器服务
|
6月前
|
C#
C# .net webapi使用swagger时显示controller注释
C# .net webapi使用swagger时显示controller注释
86 0
|
8月前
|
开发框架 .NET 中间件
Swagger的 ASP.NET Core Web API 帮助页
使用 Web API 时,了解其各种方法对开发人员来说可能是一项挑战。 Swagger 也称为OpenAPI,解决了为 Web API 生成有用文档和帮助页的问题。 它具有诸如交互式文档、客户端 SDK 生成和 API 可发现性等优点。
70 0
|
8月前
|
开发框架 JSON .NET
使用 ASP.NET Core 创建 Web API系列
使用 ASP.NET Core 创建 Web API系列
165 0
|
9月前
|
安全 API 开发者
让IIS支持.NET Web Api PUT和DELETE请求
让IIS支持.NET Web Api PUT和DELETE请求
|
9月前
|
开发框架 JSON 算法
ASP.NET Core Web API之Token验证
ASP.NET Core Web API之Token验证
145 0
|
9月前
|
开发框架 JSON 前端开发
ASP.NET Web API入门介绍(一)
ASP.NET Web API入门介绍(一)
124 0
|
XML 存储 Shell
快学会这个技能-.NET API拦截技法
怎么在不改变源码的情况下,篡改一个方法的入参?伪造返回结果?
|
开发框架 JSON 前端开发
6.3 ASP.NET Core Web API技术选择
ASP.NET Core Web API技术选择
6.3 ASP.NET Core Web API技术选择