热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

艾伟深入解析:WCFBinding模型中的绑定元素详解

本文深入解析了WCFBinding模型中的绑定元素,详细介绍了信道、信道管理器、信道监听器和信道工厂的概念与作用。从对象创建的角度来看,信道管理器负责信道的生成。具体而言,客户端的信道通过信道工厂进行实例化,而服务端则通过信道监听器来接收请求。文章还探讨了这些组件之间的交互机制及其在WCF通信中的重要性。

在上面的内容中,先后介绍了信道、信道管理器、信道监听器和信道工厂。从对象的创建来讲,信道管理器是信道的创建者。说的再具体点,客户端的信道通过信道工厂创建,服务端的信道通过信道监听器创建。但是信道工厂和信道监听器又是如果被创建出来的呢?

我们在一开始就已经说过,作为终结点三要素的绑定对象实现了所有的通信细节,并且通过创建信道栈实现了消息的传递。从这一点来说,绑定对象无疑是信道层所有通信对象的最终缔造者,所以信道工厂和信道监听器最终的创建都是靠绑定对象实现的。关于这个创建过程又和另一个重要的对象密切相关,那就是绑定元素。

1. 绑定元素(Binding Element)

绑定元素,顾名思义就是构成一个绑定对象的元素。绑定对象最根本的目的就是创建信道栈,借此实现对消息的传输、编码和基于消息交换的其他功能,比如安全、可靠传输、事务流转等等。组成信道栈的单个信道对象基于对某项单一功能的实现,在不同环境中,我们需要根据具体的需要创建相应的信道,并根据一定的顺序把这些信道组成一个完整的信道栈。对于绑定对象来说,如何实现这种灵活、自由的信道常创建方式,这得益于基于绑定元素的设计模式。

1.1. 关于绑定元素

从结构的角度讲,一个绑定对象有一系列绑定元素组成,每个绑定元素负责创建相应的信道。所以绑定元素几何的构成以及它们之间的先后顺序,决定了最终生成的信道栈中的信道组成已经它们位于栈中的先后顺序。WCF之所以在设计的时候将绑定和绑定元素分离开发,是基于灵活性、可扩展性考虑的。

在介绍信道和信道栈的时候我们说过,我们不可能、也不应该创建一个万能的信道能够提供消息交换中的所有的功能,所以我们让一个信道只承载某个单一的功能,比如传输信道专注于网络传输,消息编码信到专注于消息的编码,WCF还定义了一一系列的信道,他们分别关注与安全、可靠传输和事务流转等等。这种信道组合的设计方式使得我们可以根据具体的需求来定制我们将要创建的信道栈,让它只具有我们必须的功能,而去除不必要的功能。

同理,我们可以根据具体实际需求,将必要的绑定元素进行有序的组合,从而创建最能适合具体场景的绑定对象。由于信道可以分为必须的传输信道、消息编码信道和可选的基于某种WS-*协议实现的协议信道,与之相对地,我们的绑定元素可以分为传输绑定元素、消息编码绑定元素和协议绑定元素。

由于信道的实际创建者是信道管理器(信道工厂和信道监听器),所以绑定元素只需要实现对信道管理器的创建,而最终实现对具体信道的创建。所以绑定元素的最根本的功能就是实现对信道监听器和信道工厂的创建。这可以从所有绑定元素的基类, System.ServiceModel.Channels.BindingElement的定义上看出来:

public abstract class BindingElement
{// Methodsprotected BindingElement();protected BindingElement(BindingElement elementToBeCloned);public virtual IChannelFactory BuildChannelFactory(BindingContext context);public virtual IChannelListener BuildChannelListener(BindingContext context) where TChannel : class, IChannel;public virtual bool CanBuildChannelFactory(BindingContext context);public virtual bool CanBuildChannelListener(BindingContext context) where TChannel : class, IChannel;public abstract BindingElement Clone();public abstract T GetProperty(BindingContext context) where T : class;
}

 

BindingElement的核心方法成员有两个:BuildChannelListener和BuildChannelFactory和CanBuildChannelListener

1.2. 案例演示:如何自定义绑定元素

接下来,我们通过一个案例来演示如果自定义一个绑定元素。通过该绑定元素来创建我们在上面一个案例中创建的两个自定义信道管理器:SimpleChannelFactory和SimpleChannelListener。按照上面的命名方式,我们把这个自定义绑定元素命名为:SimpleBindingElement,下面是整个SimpleBindingElement的定义:

public class SimpleBindingElement : BindingElement
{public SimpleBindingElement(){PrintHelper.Print(this, "SimpleBindingElement");}public override BindingElement Clone(){PrintHelper.Print(this, "Clone");return new SimpleBindingElement();}public override T GetProperty(BindingContext context){PrintHelper.Print(this, string.Format("GetProperty<{0}>", typeof(T).Name));return context.GetInnerProperty();}public override IChannelFactory BuildChannelFactory(BindingContext context){PrintHelper.Print(this, "BuildChannelFactory");return new SimpleChannelFactory(context) as IChannelFactory;}public override IChannelListener BuildChannelListener(BindingContext context){PrintHelper.Print(this, "BuildChannelListener");return new SimpleChannelListener(context) as IChannelListener;}
}

SimpleBindingElement直接继承自抽象的基类BindingElement&#xff0c;对SimpleChannelFactory和SimpleChannelListener的创建分别实现在两个被重写的方法中&#xff1a;BuildChannelFactory和BuildChannelListener中。此外还重写了两个额外的方法&#xff1a;Clone和GetProperty&#xff0c;前者用于克隆一个新的绑定元素&#xff0c;后一个和定义在信道、信道管理器的同名方法一样&#xff0c;用于获取基于某种类型的属性。

2. 绑定揭秘

前面我们一直在谈论信道、信道管理器、信道监听器、信道工厂和绑定元素&#xff0c;现在我们才进体本章的主题。不过由于前面的铺垫已经很足了&#xff0c;绑定本身反而没有太多可大书特书了。如果从结构上给绑定下个定义&#xff0c;那么我的定义很简单&#xff1a;“绑定是绑定元素的有序集合”。

2.1. 绑定是绑定元素的有序集合

由于绑定的终极目标是实现对信道栈的创建&#xff0c;而对于一个信道栈来说&#xff0c;信道的构成和次序决定着该信道栈在最终消息通信中的特性与能力&#xff0c;而绑定元素有决定着信道的创建&#xff0c;所以绑定对象本身的特性与能力由构成它的所有绑定元素以及这些绑定元素之间的先后次序决定。

正因为如此&#xff0c;当我们需要判断某一个绑定类型是否支持某种特性的时候&#xff0c;可以通过查看该绑定是否具有与此特性相关的绑定元素。比如&#xff0c;我们要判断某种绑定是否支持某种类型的传输协议&#xff0c;只需要看看构成该绑定的传输绑定元素就可以了&#xff0c;WsHttpBinding的传输绑定元素是HttpTransportBindingElement&#xff0c;所以 只能支持基于HTTP或者HTTPS的传输协议&#xff1b;如果需要确定某种类型的绑定是否支持事务的流转&#xff0c;只需要查看该绑定的绑定元素集合中是否包含TransactionFlowBindingElement就可以了。

在WCF中&#xff0c;所有的绑定都直接或者间接继承自抽象基类&#xff1a;System.ServiceModel.Channels.Binding&#xff0c;我们现在来简单地分析一下这个基类。Binding实现了接口IDefaultCommunicationTimeouts。

public abstract class Binding : IDefaultCommunicationTimeouts
{public TimeSpan OpenTimeout { get; set; } public TimeSpan CloseTimeout { get; set; } public TimeSpan SendTimeout { get; set; }public TimeSpan ReceiveTimeout { get; set; }
}

 

四个默认的超时时限可以通过编程的方式显式指定&#xff0c;也可以通过配置的方式进行设置。他们的默认值分别为&#xff1a;OpenTimeout和CloseTimeout为1分钟&#xff0c;而SendTimeout和ReceiveTimeout为10分钟。

对于Binding&#xff0c;最为重要的就是如果构建组成该绑定对象的所有绑定元素集合。基于绑定元素的创建&#xff0c;通过抽象方法CreateBindingElements实现&#xff0c;所有具体的绑定类型均需要实现该方法。

public abstract class Binding : IDefaultCommunicationTimeouts
{ ... ...public abstract BindingElementCollection CreateBindingElements();
}

由于信道管理器栈创建相应的信道栈&#xff0c;而绑定创建信道管理器栈&#xff0c;因此在Binding中定义了一系列BuildChannelFactory和BuildChannelListener方法重载&#xff0c;用于创建信道工厂栈和信道监听器栈。此外&#xff0c;和BindingElement一样&#xff0c;CanBuildChannelFactory和CanBuildChannelListener用于检测绑定对象创建信道工厂和信道监听器的能力&#xff1a;

public abstract class Binding: IDefaultCommunicationTimeouts
{...public IChannelFactory BuildChannelFactory(params object[] parameters);public virtual IChannelFactory BuildChannelFactory(BindingParameterCollection parameters);public virtual IChannelListener BuildChannelListener(params object[] parameters) where TChannel : class, IChannel;public virtual IChannelListener BuildChannelListener(BindingParameterCollection parameters) where TChannel : class, IChannel;public virtual IChannelListener BuildChannelListener(Uri listenUriBaseAddress, params object[] parameters) where TChannel : class, IChannel;public virtual IChannelListener BuildChannelListener(Uri listenUriBaseAddress, BindingParameterCollection parameters) where TChannel : class, IChannel;public virtual IChannelListener BuildChannelListener(Uri listenUriBaseAddress, string listenUriRelativeAddress, params object[] parameters) where TChannel : class, IChannel;public virtual IChannelListener BuildChannelListener(Uri listenUriBaseAddress, string listenUriRelativeAddress, BindingParameterCollection parameters) where TChannel : class, IChannel;public virtual IChannelListener BuildChannelListener(Uri listenUriBaseAddress, string listenUriRelativeAddress, ListenUriMode listenUriMode, params object[] parameters) where TChannel : class, IChannel;public virtual IChannelListener BuildChannelListener(Uri listenUriBaseAddress, string listenUriRelativeAddress, ListenUriMode listenUriMode, BindingParameterCollection parameters) where TChannel : class, IChannel;public virtual bool CanBuildChannelFactory(BindingParameterCollection parameters);public bool CanBuildChannelFactory(params object[] parameters);public bool CanBuildChannelListener(params object[] parameters) where TChannel : class, IChannel;public virtual bool CanBuildChannelListener(BindingParameterCollection parameters) where TChannel : class, IChannel;
}

2.2. 案例演示&#xff1a;如何创建自定义绑定

在上一个案例演示中&#xff0c;我们创建了自定义的绑定元素&#xff1a;SimpleBindingElement&#xff0c;在案例中我们来真正使用绑定元素&#xff0c;为此我们创建一个直接继承自Binding的自定义绑定。为了简单起见&#xff0c;对于我们自定义的绑定&#xff0c;他仅仅包含三个必须的绑定元素&#xff1a;传输绑定元素和消息编码绑定元素&#xff0c;外加我们自定义的绑定元素。对于传输&#xff0c;我们采用基于HTTP协议的HttpTransportBindingElement&#xff0c;而对应消息编码&#xff0c;则采用基于文本编码方式的TextMessageEncodingBindingElement。我们索性将我们自定义的绑定命名为SimpleBinding&#xff0c;下面是SimpleBinding的定义&#xff1a;

namespace Artech.CustomChannels
{public class SimpleBinding : Binding{private string _scheme;private TransportBindingElement _transportBindingElement &#61; new HttpTransportBindingElement();private MessageEncodingBindingElement _messageEncodingBindingElement &#61; new TextMessageEncodingBindingElement();private SimpleBindingElement _SimpleBindingElement &#61; new SimpleBindingElement();public override BindingElementCollection CreateBindingElements(){BindingElementCollection elemens &#61; new BindingElementCollection();elemens.Add(this._SimpleBindingElement);elemens.Add(this._messageEncodingBindingElement);elemens.Add(this._transportBindingElement);return elemens.Clone();}public override string Scheme{get{return this._transportBindingElement.Scheme;}}}
}

对于整个SimpleBinding的定义&#xff0c;从形式上看显得异常的简单&#xff0c;仅仅是实现了定义在Binding中的抽象方法CreateBindingElements。在CreateBindingElements方法中&#xff0c;返回一个表示绑定元素集合的BindingElementCollection对象&#xff0c;在该集合中&#xff0c;包含三种类型的绑定元素&#xff0c;有上到下的顺序分别为&#xff1a;SimpleBindingElement、MessageEncodingBindingElement和HttpTransportBindingElement。此外重写了Scheme只读属性&#xff0c;它返回HttpTransportBindingElement的scheme&#xff1a;http。

WCF中的绑定模型&#xff1a;
[WCF中的Binding模型]之一: Binding模型简介
[WCF中的Binding模型]之二: 信道与信道栈&#xff08;Channel and Channel Stack&#xff09;
[WCF中的Binding模型]之三&#xff1a;信道监听器&#xff08;Channel Listener&#xff09;
[WCF中的Binding模型]之四&#xff1a;信道工厂&#xff08;Channel Factory&#xff09;
[WCF中的Binding模型]之五&#xff1a;绑定元素&#xff08;Binding Element&#xff09;
[WCF中的Binding模型]之六&#xff1a;从绑定元素认识系统预定义绑定



推荐阅读
  • 对象自省自省在计算机编程领域里,是指在运行时判断一个对象的类型和能力。dir能够返回一个列表,列举了一个对象所拥有的属性和方法。my_list[ ... [详细]
  • 本文详细探讨了HTML表单中GET和POST请求的区别,包括它们的工作原理、数据传输方式、安全性及适用场景。同时,通过实例展示了如何在Servlet中处理这两种请求。 ... [详细]
  • 在创建新的Android项目时,您可能会遇到aapt错误,提示无法打开libstdc++.so.6共享对象文件。本文将探讨该问题的原因及解决方案。 ... [详细]
  • PHP 过滤器详解
    本文深入探讨了 PHP 中的过滤器机制,包括常见的 $_SERVER 变量、filter_has_var() 函数、filter_id() 函数、filter_input() 函数及其数组形式、filter_list() 函数以及 filter_var() 和其数组形式。同时,详细介绍了各种过滤器的用途和用法。 ... [详细]
  • 本文详细介绍了 iBatis.NET 中的 Iterate 元素,它用于遍历集合并重复生成每个项目的主体内容。通过该元素,可以实现类似于 foreach 的功能,尽管 iBatis.NET 并未直接提供 foreach 标签。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 本文探讨了使用C#在SQL Server和Access数据库中批量插入多条数据的性能差异。通过具体代码示例,详细分析了两种数据库的执行效率,并提供了优化建议。 ... [详细]
  • 深入解析for与foreach遍历集合时的性能差异
    本文将详细探讨for循环和foreach(迭代器)在遍历集合时的性能差异,并通过实际代码示例和源码分析,帮助读者理解这两种遍历方式的不同之处。文章内容丰富且专业,旨在为编程爱好者提供有价值的参考。 ... [详细]
  • JavaScript 基础语法指南
    本文详细介绍了 JavaScript 的基础语法,包括变量、数据类型、运算符、语句和函数等内容,旨在为初学者提供全面的入门指导。 ... [详细]
  • 哈密顿回路问题旨在寻找一个简单回路,该回路包含图中的每个顶点。本文将介绍如何判断给定的路径是否构成哈密顿回路。 ... [详细]
  • Struts与Spring框架的集成指南
    本文详细介绍了如何将Struts和Spring两个流行的Java Web开发框架进行整合,涵盖从环境配置到代码实现的具体步骤。 ... [详细]
  • Ihaveastringwithquotesaroundthepathasfollows:我在路径周围有一个带引号的字符串,如下所示:C:\ProgramFiles(x ... [详细]
  • 在Oracle数据库中,使用Dbms_Output.Put_Line进行输出调试时,若单行字符超过255个,则会遇到ORA-20000错误。本文介绍了一种有效的方法来处理这种情况,通过创建自定义包和视图,实现对长字符串的分割和正确输出。 ... [详细]
  • 使用lambda表达式排序Collections.sort(temp,(Stringa,Stringb)-{returnb.compareTo(a);});Collections ... [详细]
  • CentOS 6.5 上安装 MySQL 5.7.23 的详细步骤
    本文详细介绍如何在 CentOS 6.5 系统上成功安装 MySQL 5.7.23,包括卸载旧版本、下载安装包、配置文件修改及启动服务等关键步骤。 ... [详细]
author-avatar
益林代表_610
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有