[WCF REST] WebHttpBinding与消息编码

不论是我们采用SOAP还是REST架构风格,运行时框架体系依然不曾改变,终结点也仍旧是通信的核心。在Web HTTP编程模型中,我们采用基于WebHttpBinding绑定的终结点。绑定是一组相关绑定元素的有序组合,绑定的特性与能力决定于它包含的绑定元素,在这里我们通过分析绑定元素的方式来剖析WebHttpBinding绑定与其它绑定有何不同。采用HTTP/HTTPS通信协议的WebHttpBinding具有一些与WSHttpBinding/WS2007HttpBinding相同的属性,在这里我们只关心如下定义的Security属性。

   1: public class WebHttpBinding : Binding, IBindingRuntimePreferences
   2: {
   3:     //其它成员
   4:     public WebHttpSecurity Security { get; }
   5: }
   6: public sealed class WebHttpSecurity
   7: {
   8:     // 其它成员
   9:     public WebHttpSecurityMode Mode { get; set; }
  10:     public HttpTransportSecurity Transport { get; }
  11: }
  12: public enum WebHttpSecurityMode
  13: {
  14:     None,
  15:     Transport,
  16:     TransportCredentialOnly
  17: }

基于SOAP的绑定一般具有两种基本的安全模式,即Message和Transport模式。对于前者,它是完全建立在WS-Security为核心的安全协议之上的,而整个WS-*协议簇都是基于SOAP的,所以自然不能应用在WebHttpBinding上,所以它只能通过HTTPS提供针对Transport模式的安全支持。具体来说,通过枚举WebHttpSecurityMode表示的安全模式具有如下三个选项:

  • None:HTTP 请求未使用任何安全性;
  • Transport:HTTP 请求使用传输级安全性;
  • TransportCredentialOnly:仅提供基于 HTTP 的客户端身份验证。

一、WebHttpBinding的绑定元素

现在我们根据上述三种不同的安全模式创建相应的WebHttpBinding对象,然后通过如下的程序在控制台中答应出所有的绑定元素类型。

   1: static void Main(string[] args)
   2: {
   3:     WebHttpBinding binding = new WebHttpBinding(WebHttpSecurityMode.None);
   4:     ListBindingElements(binding);
   5:  
   6:     binding = new WebHttpBinding(WebHttpSecurityMode.Transport);
   7:     ListBindingElements(binding);
   8:  
   9:     binding = new WebHttpBinding(WebHttpSecurityMode.TransportCredentialOnly);
  10:     ListBindingElements(binding);
  11: }
  12: static void ListBindingElements(WebHttpBinding binding)
  13: {
  14:     int index = 1;
  15:     Console.WriteLine(binding.Security.Mode + ":");
  16:     foreach (var element in binding.CreateBindingElements())
  17:     { 
  18:         Console.WriteLine("{0}. {1}", index++, element.GetType().FullName);
  19:     }
  20:     Console.WriteLine();
  21: }

上述的程序执行之后会在控制台上产生如下的输出,从中我们不难看出三个WebHttpBinding均由一个消息编码元素和传输元素组成,我们知道这两种绑定元素最所有类型的绑定所必需的。

   1: None:
   2: 1. System.ServiceModel.Channels.WebMessageEncodingBindingElement
   3: 2. System.ServiceModel.Channels.HttpTransportBindingElement
   4:  
   5: Transport:
   6: 1. System.ServiceModel.Channels.WebMessageEncodingBindingElement
   7: 2. System.ServiceModel.Channels.HttpsTransportBindingElement
   8:  
   9: TransportCredentialOnly:
  10: 1. System.ServiceModel.Channels.WebMessageEncodingBindingElement
  11: 2. System.ServiceModel.Channels.HttpTransportBindingElement

对于WebHttpBinding的两个绑定元素来说,由于它通过HTTPS提供针对Transport安全的支持,所以当安全模式为Transport时对应的传输绑定元素为HttpsTransportBindingElement,对于其余两种安全模式则直接采用HttpTransportBindingElement作为传输绑定元素。现在我们着重讨论是作为消息编码绑定元素的WebMessageEncodingBindingElement类型,以及它涉及的消息编码机制。

二、消息编码

我们先来看看WebMessageEncodingBindingElement的基本的定义。如下面的代码片断所示,它是MessageEncodingBindingElement的子类,并且具有与TextMessageEncodingElement类似的属性定义。其中MaxReadPoolSize和MaxWritePoolSize表示表示无需分配新的XmlDictionaryReader/XmlDictionaryWriter便可以读取的便可同时读取/写入的最大消息数,默认值分别是64和16。ReaderQuotas属性返回用于约束读取的XML的复杂度的XmlDictionaryReaderQuotas对象,而WriteEncoding属性表示采用的字符编码类型,默认采用UTF-8编码方式。由于WebHttpBinding不使用SOAP,表示消息版本的MessageVersion属性自然返回None,如果我们对该属性进行设置,指定的属性值也只能是MessageVersion.None。

   1: public sealed class WebMessageEncodingBindingElement : MessageEncodingBindingElement,...
   2: {   
   3:     //其它成员
   4:     public override MessageEncoderFactory CreateMessageEncoderFactory();
   5:  
   6:     public bool CrossDomainScriptAccessEnabled {get; set; } 
   7:     public WebContentTypeMapper ContentTypeMapper { get; set; }
   8:  
   9:     public int MaxReadPoolSize { get; set; }
  10:     public int MaxWritePoolSize { get; set; }
  11:     public override MessageVersion MessageVersion { get; set; }
  12:     public XmlDictionaryReaderQuotas ReaderQuotas { get; }
  13:     public Encoding WriteEncoding { get; set; }
  14: }

除此之外,WebMessageEncodingBindingElement具有CrossDomainScriptAccessEnabled 和ContentTypeMapper这两个重要的属性。前者表示是否支持跨域(Corss-Domain)脚本访问,默认值为False。后者类型为WebContentTypeMapper。WebContentTypeMapper用于进行消息的内容类型(Content Type,有时候也成为媒体类型或者MIME类型)与具体的格式(比如XML、JSON等)之间的映射。

   1: public abstract class WebContentTypeMapper
   2: {
   3:     protected WebContentTypeMapper();
   4:     public abstract WebContentFormat GetMessageFormatForContentType(string contentType);
   6: }
   7: public enum WebContentFormat
   8: {
   9:     Default,
  10:     Xml,
  11:     Json,
  12:     Raw
  13: }

如上面的代码所示,WebContentTypeMapper是一个抽象类,包含的唯一的抽象方法GetMessageFormatForContentType用于根据指定的内容类型返回与之匹配的通过枚举WebContentFormat表示的内容格式。WebContentFormat枚举的Xml、JSON和Raw体现了Web HTTP编程模型支持三种基本格式,其中Raw表示原始的二进制。

最终的消息编码/解码工作是通过继承自MessageEncoder的消息编码器实现的,消息编码器又是通过继承自MessageEncoderFactory的编码器工厂创建出来的,而消息编码绑定元素最终通过方法CreateMessageEncoderFactory创建了编码器工厂。对于WebMessageEncodingBindingElement来说,它的CreateMessageEncoderFactory方法会创建一个具有如下定义的WebMessageEncoderFactory对象。

   1: internal class WebMessageEncoderFactory : MessageEncoderFactory
   2: {
   3:     public WebMessageEncoderFactory(Encoding writeEncoding, int maxReadPoolSize,int maxWritePoolSize, XmlDictionaryReaderQuotas quotas, 
   4:         WebContentTypeMapper contentTypeMapper, bool javascriptCallbackEnabled);
   5:     public override MessageEncoder Encoder { get; }
   6:     public override MessageVersion MessageVersion { get; }
   7: }
   8:   

WebMessageEncoderFactory是一个继承自MessageEncoderFactory的内部类型。除了布尔类型的参数javascriptCallbackEnabled对应着WebMessageEncodingBindingElement的属性CrossDomainScriptAccessEnabled之外,WebMessageEncoderFactory的构造函数参数与WebMessageEncodingBindingElement的同名属性一一对应。代表消息版本的MessageVersion属性依然返回None,而真正用于最终消息编码/解码工作的是通过Encoder属性返回的具有如下定义的WebMessageEncoder对象。

   1: internal class WebMessageEncoderFactory : MessageEncoderFactory
   2: {    
   3:     private class WebMessageEncoder : MessageEncoder
   4:     {
   5:         //其他成员
   6:         private MessageEncoder TextMessageEncoder { get; }
   7:         private MessageEncoder JsonMessageEncoder { get; }
   8:         private MessageEncoder RawMessageEncoder { get; }
   9:     }
  10: }

如上面的代码片断所示,WebMessageEncoder实际上是内嵌于WebMessageEncoderFactory类型中继承自MessageEncoder的内部类型。WebMessageEncoder本身并不真正地实施消息的编码/解码,最终的消息编码/解码工作是通过三个属性TextMessageEncoder、JsonMessageEncoder和RawMessageEncoder体现的具体消息编码器完成的,而它们又分别对应着通过WebContentFormat枚举表示的三种内容类型Xml、JSON和Raw。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏有趣的django

7.python常用模块

time模块 常用表示时间方式: 时间戳,格式化的时间字符串,元组(struct_time) UTC(Coordinated Universal Time,世界...

49211
来自专栏Android先生

Java多线程-带你认识Java内存模型,内存分区,从原理剖析Volatile关键字

地址:https://juejin.im/post/59f8231a5188252946503294

1093
来自专栏服务端技术杂谈

Golang笔记

静态编译 编译时一个将源代码翻译成低级语言的过程。编译过程比较慢,在设计Go时,编译速度是主要的设计目标之一。静态类型意味着变量必须指定一个类型,如整形,字符串...

3004
来自专栏林德熙的博客

C#判断文件是否被混淆

可以使用混淆工具对一个DLL 和 exe 进行混淆。 但是如何知道一个文件是否已经混淆了。 在发布之前,需要知道是不是有文件忘了混淆。

2532
来自专栏专注 Java 基础分享

虚拟机类加载机制

虚拟机把字节码文件从磁盘加载进内存的这个过程,我们可以粗糙的称之为「类加载」,因为「类加载」不仅仅是读取一段字节码文件那么简单,虚拟机还要进行必要的「验证」、「...

4707
来自专栏QQ会员技术团队的专栏

JavaScript引擎分析

JavaScript引擎分析 一. JavaScript简介 JavaScript是一种动态类型的脚本语言;在1995年时,由Netscape公司的Brend...

2525
来自专栏C/C++基础

Linux命令(11)——col命令

col命令是一个标准输入文本过滤器,它从标准输入读取内容,输出到标准输出。在许多UNIX说明文件里,包含控制字符。当我们运用Shell特殊字符>和>>,把说明文...

1022
来自专栏吴伟祥

Jmockdata随机模拟 Java 数据插件

     Jmockdta是一款实现模拟JAVA类型或对象的实例化并随机初始化对象的数据的工具框架。

1082
来自专栏葡萄城控件技术团队

C#:异步编程和线程的使用(.NET 4.5 )

异步编程和线程处理是并发或并行编程非常重要的功能特征。为了实现异步编程,可使用线程也可以不用。将异步与线程同时讲,将有助于我们更好的理解它们的特征。 本文中涉及...

2235
来自专栏李航的专栏

Shell 主要逻辑源码级分析:SHELL 运行流程 (1)

分享一下在学校的时候分析shell源码的一些收获,帮助大家了解shell的一个工作流程,从软件设计的角度,看看shell这样一个历史悠久的软件的一些设计优点和缺...

2.1K0

扫码关注云+社区

领取腾讯云代金券