`
varsoft
  • 浏览: 2422227 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

[原创]WCF后续之旅(1): WCF是如何通过Binding进行通信的

阅读更多

《我的WCF之旅》系列自开篇以来,得到了园子里很多朋友的厚爱,并荣登了博客园2007年度系列博文Top 10。由于工作原因,沉寂了几个月,今天开始WCF新的旅程。如果说《我的WCF之旅》主要是对WCF基本原理概括性介绍,而对于这个新的系列,我将和大家分享我对WCF的一些实现机制、设计原理的理解,以及我在实际的项目开发中的一些实践经验(比如在后续的一些文章中,我将介绍通过WCF Extension实现一些在真正的分布式项目开发中很有现实意义的功能)。

Windows Communication Foundation,顾名思义,就是一个在Windows平台下进行如何进行Communication的基础构造(Infrastructure)。由于WCF的核心还是Communication,这个新的系列就先来讨论WCF如何进行Communication的。通过本篇文章,你将对WCF的通信机制有一个总体的认识,了解到一些和通信相关的概念, 比如:CommunicationChannelChannel ListenerChannel FactoryBindingElement,Channel Shape等等。

我们已经很清楚了,WCF的通信是通过Endpoint来完成的:Service Provider将WCF service通过Endpoint暴露出来供Service consumer调用,而Service consumer通过与之相匹配的Endpoint来调用service。"Endpoint=ABC”,大家一定也牢记于心。就Endpoint包含的这3个元素而言,Address解决了寻址的问题,代表如何定位和标识对应的Endpoint,而Contract在对Service提供的功能、操作(Service Contract)以及数据(Data contract、Message contract和Fault contract)的抽象表示。而真正实现了通信功能的则是Binding

1、Binding实现了所有的通信细节

总体上讲, WCF主要有两个层次构成:Channel LayerService Layer. 前者通过Channel Stack实现Message的传输,而后者对开发人员提供了一个Programming Mode。对于一般的WCF开发人员,不会接触到Channel Layer,而只会调用Service Layer提供的API而以。

但是,如果你需要真正地认识WCF 整个通信框架,对Channel Layer的了解绝对是有必要的。在我看来,WCF最吸引我的地方不是它自己为我们提供了完备的通信相关的实现,而在于WCF是一个极具可扩展性的通信框架,无论是Channel Layer还是Service Layer,我们都可以通过WCF Extension对WCF进行自由的扩展以适应我们的具体需求, 在本系列后续的文章中我将向大家介绍一系列有用的扩展。如何你想充分利用WCF提供给我们的扩展性,对Channel Layer的了解基本上是必须的。

严格地讲,Binding是Service Layer层面上的概念,不过它是由Service Layer转入Channel的入口,也是从Channel Layer到Service Layer的中介。我们说Binding实现了所有通信细节,是站在Service Layer角度来讲的。至于Binding如何实现通信细节,则是通过Channel Layer来实现的。

为了让大家对Binding如何实现通过现有一个感性的认识,我们来看一个简单的例子。

2. Demo: 直接通过Binding进行通信

这个例子通过简简单单的几行代码,通过BasicHttpBinding实现了通信的全过程。该程序很想我们传统的基于Socket的程序:Server端Listen request=>Accept request=>Process request=>Send reply;Client端Send request=>Receive reply。此外通过这个这个简单的程序,将引出Channel Layer一系列重要的对象,比如ChannelRequestChannel、ReplyChannel、Channel ListenerChannel Factory等等。

整个应用有两个Console application构成,分别模拟Server和Client.

wcf2_01_01

我们先来看看Server端的代码:

namespace Artech.MessagingViaBinding.Server
{
class Program
{
staticvoid Main(string[] args)
{
Uri address
=new Uri("http://127.0.0.1:9999/messagingviabinding");
BasicHttpBinding binding
=new BasicHttpBinding();
IChannelListener
<IReplyChannel> channelListener = binding.BuildChannelListener<IReplyChannel>(address);
channelListener.Open();
IReplyChannel channel
= channelListener.AcceptChannel();
channel.Open();
Console.WriteLine(
"Begin to listen ");
while (true)
{
RequestContext context
=channel.ReceiveRequest(new TimeSpan(1,0,0));
Console.WriteLine(
"Receive a request message:\n{0}", context.RequestMessage);
Message replyMessage
= Message.CreateMessage(MessageVersion.Soap11, "http://artech.messagingviabinding", "This is a mannualy created reply message for the purpose of testing");
context.Reply(replyMessage);
}

}

}

}

我来简单介绍一些上面这段代码的逻辑:

  • 创建Uri对象,代表监听的URI:
    EndpointAddress address = new EndpointAddress("http://127.0.0.1:9999/messagingviabinding");
  • 创建BasicHttpBinding对象,我们正是通过它来使用所有的通信功能:
    BasicHttpBinding binding = new BasicHttpBinding();
  • 通过binding对象创建IChannelListener对象,并调用Open方法打开它:
    IChannelListener<IReplyChannel> channelListener = binding.BuildChannelListener<IReplyChannel>(address);
    channelListener.Open();
  • 通过IChannelListener对象创建IReplyChannel 并调用Open方法打开它:
    IReplyChannel channel = channelListener.AcceptChannel();
    channel.Open();

  • 在While循环中监听来自client端的request,一旦request抵达, 调用IReplyChannel 的ReceiveRequest方法,并得到一个RequestContext 对象,通过RequestContext 对象可以得到request message并打印出来: RequestContext context=channel.ReceiveRequest(new TimeSpan(1,0,0));
    Console.WriteLine("Receive a request message:\n{0}", context.RequestMessage);

  • 创建一个Reply message,借助得到的RequestContext 对象发送回client端:
    Message replyMessage = Message.CreateMessage(MessageVersion.Soap11, "http://artech.messagingviabinding", "This is a mannualy created reply message for the purpose of testing");
    context.Reply(replyMessage);

再来看看Client端的代码:

namespace Artech.MessagingViaBinding.Client
{
class Program
{
staticvoid Main(string[] args)
{
EndpointAddress address
=new EndpointAddress("http://127.0.0.1:9999/messagingviabinding");
BasicHttpBinding binding
=new BasicHttpBinding();
IChannelFactory
<IRequestChannel> chananelFactory= binding.BuildChannelFactory<IRequestChannel>();
chananelFactory.Open();
IRequestChannel channel
= chananelFactory.CreateChannel(address);
channel.Open();
Message requestMessage
= Message.CreateMessage(MessageVersion.Soap11, "http://artech/messagingviabinding", "The is a request message manually created for the purpose of testing.");
Message replyMessage
= channel.Request(requestMessage);
Console.WriteLine(
"Receive a reply message:\n{0}", replyMessage);
channel.Close();
chananelFactory.Close();
Console.Read();
}

}

}

我们也来简单分析一下上面这段代码的逻辑:

  • 创建EndpointAddress 对象,这和Server的Uri一致,代表请求的地址:
    EndpointAddress address = new EndpointAddress("http://127.0.0.1:9999/messagingviabinding");
  • 创建BasicHttpBinding对象,通过实现向Server端的发送Request,并接收Reply:
    BasicHttpBinding binding = new BasicHttpBinding();
  • 通过Binding对象创建IChannelFactory对象并调用Open方法打开它:IChannelFactory<IRequestChannel> chananelFactory= binding.BuildChannelFactory<IRequestChannel>();
    chananelFactory.Open();
  • 通过IChannelFactory对象创建IRequestChannel 对象并调用Open方法打开它:
    IRequestChannel channel = chananelFactory.CreateChannel(address);
    channel.Open();
  • 创建Request message通过Channel对象发送到Server端,Request方法调用会返回一个Message对象代表从Server端发送回来的Reply message:
    Message requestMessage = Message.CreateMessage(MessageVersion.Soap11, "http://artech/messagingviabinding", "The is a request message manually created for the purpose of testing.");
    Message replyMessage = channel.Request(requestMessage);
    Console.WriteLine("Receive a reply message:\n{0}", replyMessage);

        我们来看看程序运行的结果,下面是Client端的截图:

        wcf2_01_02

        这是Server端的截图:

        wcf2_01_03

        3. Channel

        同传统的通信框架一样, 比如.NET Remoting,最终的通信功能通过Communication Channel来实现。同.NET Remoting一样,在Messaging过程中需要实现不同功能实现, 比如TransportEncodingSecurityTransaction EnlistReliable MessagingCompressionLogging等等,这些功能不可能有一个单一的Channel来实现。从可扩展性考虑,我们也没有必要、也没有可能创建一个万能Channel,我们希望的情况是这样的:一个Channel专注于Messaging过程中某个单一的功能实现,当我们需要某个具体的功能的时候,可以通过插件的形式自由地将对应的Channel加进来就可以了。 而WCF本身也是这样设计的:整个Messaging过程通过一连串Channel来实现,这些Channel按照一定的顺序组成一个Channel stack。由于Messaging首先是基于某种Protocol的Transport, 比如http、TCP、MSMQ、ICP等等,Transport channel在Channel stack中一定是必须的。而且对Transport channel在整个channel stack的位置也有固定的要求:在Sender方的最后一个,Receiver方的第一个。

        不管Channel具体完成怎样的功能,他们都可以看成是一个个Message处理器,这包括为了某种需求添加、修改Soap header;压缩整个Message、或者Message body; 对Message进行签名或者加密等等。

        在WCF中,所有的Channel都直接或者间接实现一个Interface:System.ServiceModel.Channels.IChannel。通过一个WCF还定义了一个base class:ChannelBase。ChannelBase实现了一些Channel基本的功能,所以我们在自定义Channel的时候一般继承ChannelBase。

        4. Channel Shape

        由于WCF在进行Messaging的时候可以采用不同的消息交换模式(MEP-Message Exchange Pattern)。 在不同的MEP中,发送方Channel和接收方Channel在Messaging中所扮演的角色是不相同的。比如我们最常见的Request/Reply MEP中,发送方负责向接收方发送请求并接受回复,而接收方则负责向发送方回复请求,所以发送方的Channel是一个Request Channel,接收方Channel是一个Reply Channel。而对于One-way MEP中,发送方只需要向接收方而不需要接收来自接受方的回复,而对于接收方来说,仅仅需要接受来自发送方的消息而不需要向发送放回复消息,所以One-way发送方的Channel是一种Output Channel,而接收方的Channel是Input Channel。而对于Duplex 方式进行Messaging双方具有相同角色,即负责相对方发送消息,又需要接受对方发送过来的消息,所以此种MEP对应的Channel是Duplex Channel。实际上Duplex Channel = Output Channel + Input Channel。

        WCF专门用一个专门的术语来表述这种不能得MEP对消息交互双方Channel的不同要求:Channel Shape。我们常见的Channel Shape有以下四种:

        • Datagram:数据报方式,采用One-way的消息交换模式。
        • Request/Reply:请求/恢复方式,采用传统的Request/Reply 消息交换模式。
        • Duplex:双向通信,采用Duplex消息交换模式。
        • P2P :点对点方式通信, 采用Duplex消息交换模式。

        由于在不同的MEP中,消息交互双方Channel在整个消息交换过程所扮演的角色时不同的。同理,对于不同Channel shape, 消息的发送放和接受方需要不同的Channel。System.ServiceModel.Channels namespace定义了相应的Channel interface来表示这些Channel:IRequestChannel, IReplyChannel, IOutputChannel, IInputChannel, IDuplexChannel。这些channel interface与Channel shape之间的对应关系如下表所示:

        MEP Sender Receiver
        Datagram IOutputChannel IInputChannel
        Request/Reply IRequestChannel IReplyChannel
        Duplex IDuplexChannel IDuplexChannel
        P2P IDuplexChannel IDuplexChannel

        我们回顾一下我们上面的Sample,是否还记得在Client端代码中,我们通过IChannelFactory对象的CreateChannel方法创建了一个IRequestChannel, 而在Server端的代码中通过IChannelListener对象的AcceptChannel方法创建了一个IReplyChannel。那就是应该我们模拟的是传统的Request/Reply MEP。

        5. Channel Manager: Channel Listener & Channel Factory

        通过上面的介绍,我们知道了所有的Messaging功能最终都是通过Channel stack来完成的。但是我们在什么时候创建这些Channel,通过什么方式创建它们呢?

        在WCF中,这些Channel对象,无论是处于发送方还是接受方,都不会直接创建他们。所有创建channel的功能都是通过一组特殊的对象来实现的。我们把这类对象叫做Channel Manager。不过Channel Manager这个名字不是很常用。你可以经常通道的是它的两个别名:Channel Listener和Channel Factory.

        对于Channel的创建,创建方式在发送方和接收方是完全不一样的。对于方法来将,channel的创建方式和简单,也很直接,就是单纯的创建Channel并使用它向接受方发送消息,并接受恢复(如果不是Datagram channel shape),说发送方的Channel manager本质上就是一个Channel factory。

        而对于接受方来讲,Channel manager实际上起着监听者的作用。它和一个固定的Uri绑定,不断监听来自不同发送方的请求,一旦某个请求被监听到,channel manager创建一个Channel来接受该请求,所以接受方的Channel manager被称作Channel listener。

        一个一个channel连接形成一个Stack,通过一个个的Channel factory或者Channel listener也形成一个Stack。所以我们经常所说的Channel stack往往只的是Channel stack & Channel factory/listener stack.

        我们在回到我们上面的Sample,对于Client端的IRequestChannel对象是通过我们创建的IChannelFactory的CreateChannel方法创建,而Server端的IReplyChannel则是通过IChannelListener的AcceptChannel方法创建。

        6. Binding & Binding Element

        通过以上的叙述,我们实际上对WCF channel layer进行了大致的介绍。我们说channel layer处于Service layer以下,而且一般的WCF开发人员一般不会直接和Channel layer进行交互,而仅仅会通过Service layer提供的API来实现WCF提供的功能。channel layer和Service layer是通过什么方式实现无缝的连接呢?答案是Binding.

        上面我们说了所有的消息交互功能都是通过Channel stack来实现,而组成Channel stack的一个个的Channel又是通过Channel factory和Channel listener来创建的。Channel factory和Channel listener又是通过什么创建的呢?答案也是Binding。这点通过我们上面的Sample也可以看出来:我们通过BasicHttpBinding的BuildChannelFactory方法和BuildChannelListener方法创建了IChannelFactory对象和IChannelListener对象。

        IChannelFactory<IRequestChannel> chananelFactory= binding.BuildChannelFactory<IRequestChannel>();
        IChannelListener
        <IReplyChannel> channelListener = binding.BuildChannelListener<IReplyChannel>(address);

        我们在进一步深究Binding是如何创建IChannelFactory对象和IChannelListener对象。一个Binding由BindingElement collection组成, 构成BindingElement collection的元素是一个个的BindingElement。BindingElement的最重要的功能就是创建IChannelFactory和IChannelListener对象。每个BindingElement继承自BindingElement abstract class 。下面是BindingElement的定义:

        publicabstractclass BindingElement
        {
        // Methods
        protected BindingElement();
        protected BindingElement(BindingElement elementToBeCloned);
        publicvirtual IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context);
        publicvirtual IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context) where TChannel : class, IChannel;
        publicvirtualbool CanBuildChannelFactory<TChannel>(BindingContext context);
        publicvirtualbool CanBuildChannelListener<TChannel>(BindingContext context) where TChannel : class, IChannel;
        publicabstract BindingElement Clone();
        internal T GetIndividualProperty<T>() where T : class;
        publicabstract T GetProperty<T>(BindingContext context) where T : class;
        internalvirtualbool IsMatch(BindingElement b);
        }

        7. 如何对Channel Layer进行扩展

        在上面已经说了,WCF的一个最大的特性在于具有很强的扩展性。无论是Channel Layer还是Service,你都可以很自由地进行扩展,而这些扩展在具体的项目中往往具有很强的使用性。在我当前的项目中,我就使用了很多这方面的扩展,在后续的章节中,我将会将这些与大家分享。

        对于Channel Layer的扩展,一般集中在通过创建一些自定义的Channel来完成现有Channel不能完成的功能,比如你可以需要创建一个channel来完成对Message Body的压缩功能。单独创建channel往往是不够的,我们需要创建与之配套的其他的一些对象,不如Channel factory、Channel listerner、Binding element等等。

        在下一篇文章中,将为大家介绍如何创建这些对象。

        WCF后续之旅:
        [原创]WCF后续之旅(1): WCF是如何通过Binding进行通信的
        [原创]WCF后续之旅(2): 如何对Channel Layer进行扩展——创建自定义Channel
        [原创]WCF后续之旅(3): WCF Service Mode Layer 的中枢—Dispatcher
        [原创]WCF后续之旅(4):WCF Extension Point 概览
        [原创]WCF后续之旅(5): 通过WCF Extension实现Localization
        [原创]WCF后续之旅(6): 通过WCF Extension实现Context信息的传递
        [原创]WCF后续之旅(7):通过WCF Extension实现和Enterprise Library Unity Container的集成
        [原创]WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成
        [原创]WCF后续之旅(9):通过WCF的双向通信实现Session管理[Part I]
        [原创]WCF后续之旅(9): 通过WCF双向通信实现Session管理[Part II]
        [原创]WCF后续之旅(10): 通过WCF Extension实现以对象池的方式创建Service Instance


        我的WCF之旅:
        [原创]我的WCF之旅(1):创建一个简单的WCF程序
        [原创]我的WCF之旅(2):Endpoint Overview
        [原创]我的WCF之旅(3):在WCF中实现双向通信(Bi-directional Communication)
        [原创]我的WCF之旅(4):WCF中的序列化(Serialization)- Part I
        [原创]我的WCF之旅(4):WCF中的序列化(Serialization)- Part II
        [原创]我的WCF之旅(5):Service Contract中的重载(Overloading)
        [原创]我的WCF之旅(6):在Winform Application中调用Duplex Service出现TimeoutException的原因和解决方案
        [原创]我的WCF之旅(7):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的继承
        [原创]我的WCF之旅(8):WCF中的Session和Instancing Management
        [原创]我的WCF之旅(9):如何在WCF中使用tcpTrace来进行Soap Trace
        [原创]我的WCF之旅(10): 如何在WCF进行Exception Handling
        [原创]我的WCF之旅(11):再谈WCF的双向通讯-基于Http的双向通讯 V.S. 基于TCP的双向通讯
        [原创]我的WCF之旅(12):使用MSMQ进行Reliable Messaging
        [原创]我的WCF之旅(13):创建基于MSMQ的Responsive Service

        分享到:
        评论

        相关推荐

          了解WCF内建Binding

          了解WCF内建的多个Binding.编码等

          WCF https binding 实例

          c# 利用WCF实现https 安全通信

          WCF专题系列(1):深入WCF寻址Part1

          概述众所周知,WCF服务的所有通信都是通过服务的终结点发生的,每个服务终结点都包含一个地址Address、一个绑定Binding和一个契约Contract。契约指定可用的操作,绑定指定如何与服务进行通信,而地址指定查找服务的...

          WCF从理论到实践.CHM

          CF从理论到实践(1):揭开神秘面纱;...WCF从理论到实践(3):八号当铺之黑色契约;WCF从理论到实践(4):路在何方;WCF从理论到实践(5):Binding细解;WCF从理论到实践(6):WCF架构;WCF从理论到实践(7):消息交换模式

          WCF框架服务端,WCF接口,基于控制台程序

          &lt;endpoint address="WCFServices" bindingConfiguration="BasicHttpBinding_IWCFServices" binding="basicHttpBinding" contract="RuralService.IWCFServices" /&gt; &lt;baseAddresses&gt; ...

          wcf客户端(测试服务端)

          &lt;endpoint address="WCFServices" bindingConfiguration="BasicHttpBinding_IWCFServices" binding="basicHttpBinding" contract="RuralService.IWCFServices" /&gt; &lt;baseAddresses&gt; ...

          WCF从理论到实践系列之二

          (5):Binding细解本文的出发点:通过阅读本文,您能了解以下知识:WCF中的Binding是什么?Binding的组成?BindingElement的分类?Binding描述了那些层面的信息?选择正确的Binding本文适合的读者:本文适合WCF的初学...

          WCF中使用nettcp协议进行通讯的方法

          如何在wcf中用net tcp协议进行通讯,一个打开Wcf的公共类。比较好好,可以记下来。 配置文件中注意配置 Service,binding,behaviors. Service中配置endpoint 指明abc ,binding中配置tcp通讯的要关参数,behaivor中...

          WCF EF DataBinding的示例代码

          DataGridView 如何利用 BindingSource 绑定1:N的多表数据。ORM使用ADO.NET Entity Framework EF的DB路径写的绝对路径,所以请自行修改。 Northwind.mdf 在工程目录下。

          wcf流传输分块

          乐意与人交流学习。 ContractDescription contract = ... NetTcpBinding binding = new NetTcpBinding(); binding.MaxReceivedMessageSize = 1024 * 1024 * 30; binding.ReceiveTimeout = TimeSpan.FromMinutes(5);

          C# 在Winform中发布WebService

          完整的服务端及客户端调用程序,在win7+ vs2015环境运行通过. 一、说明 1、创建winfrom应用程序;(或者是控制台项目) 2、在项目中添加一个WCF服务,并实现服务; 3、在需要启动WebService服务的地方启动该服务即可;...

          Microsoft Windows Communication Foundation 4.0 Cookbook for Developing SOA Applications

          The Windows Communication Foundation 4.0 (WCF 4.0) is a .NET-based application programming interface for building and running connected systems. It enables secure and reliable communication among ...

          dot NET技术企业高级培训PPT

          第五部分 WCF开发技术(1.5天) 第六部分-项目实战(1.5天) 详细内容: 第一部分 .NET框架(0.5天) 1. 了解.NET之前诞生前的世界 2. Microsoft .NET 框架结构 3. Microsoft .NET 框架结构 4. .NET Framework 概述 ...

          X509自定义用户验证授权basicBinding

          1.修改WCF服务应用程序 2.Web.config中修改 以下实例中: www.nqe.net 为个人WCF服务应用程序网址 nqe.net" 为正式X509证书的友好名称 1.CustomAuthorizeAuthenticate\DataProvider.cs文件中的 string ...

          CSDN 微软技术高级讲师.NET技术企业高级培训PPT

          第六部分 WPF+WCF项目实战(1.5天) (1) 项目开发-聊天室基于WPF+WCF的聊天室 (2) 需求分析和功能设计 (3) 聊天室系统详细设计 (4) 聊天室契约设计 (5) 聊天室实现: 宿主服务器 (6) 聊天室实现客户端 ...

          Pro C# 7: With .NET and .NET Core

          Chapter 1: The Philosophy of .NET Chapter 2: Building C# Applications Part II: Core C# Programing Chapter 3: Core C# Programming Constructs, Part I Chapter 4: Core C# Programming Constructs, Part II ...

          Applied.WPF.4.in.Context(第1版)

          中文名: Applied WPF 4 in Context (第1版) 原名: Applied WPF 4 in Context 作者: Raffaele Garofalo 资源格式: PDF 出版社: Apress书号: 978-1430234708发行时间: 2011年05月24日 地区: 美国 语言: 英文 简介: ...

          WCFSecurityGuide

          communication, as well as WCF binding configurations. • Part III – Intranet Application Scenarios shows you a set of end-to-end intranet application scenarios that you can use to jump-start your ...

        Global site tag (gtag.js) - Google Analytics