WCF客户端运行时架构体系详解[下篇]

当基于某个终结点创建的ChannelFactory<TChannel>被开启的之后,位于服务模型层的客户端运行时框架被成功构建。站在编程的角度看ChannelFactory<TChannel>,它就是一个创建用于服务调用的服务代理对象的工厂。由于服务调用需要借助于服务代理来完成,我们很有必要从整个客户端运行架构层面来了解服务代理和基于服务代理的服务调用是如何实现的。

目录
一、服务代理是一个透明代理
二、服务调用的流程
      操作选择
      输入参数检验
      序列化请求消息
      请求消息的发送和回复消息的接收
      回复消息的检验
      反序列化回复消息
      检验返回值(或者ref/out参数)

一、服务代理是一个透明代理

如果你阅读了《WCF技术剖析(卷1)》第8章《客户端(Client)》,你应该知道通过ChannelFactory<TChannel>创建的服务代理对象是一个“透明代理(Transparent Proxy)”对象。而这可以通过调用RemotingServices的静态方法IsTransparentProxy来检验。为此我写了如下一段简单的检验程序,而输出的结果证实了“服务代理是透明代理”的结论。

   1: using (ChannelFactory<ICalculate> channelFactory = new ChannelFactory<ICalculate>("calculateservice"))
   2: {
   3:     ICalculate calculator = channelFactory.CreateChannel();
   4:     bool isTransparentProxy = RemotingServices.IsTransparentProxy(calculator);
   5:     Console.WriteLine("Service porxy is a transparent proxy? {0}.", isTransparentProxy ? "Yes" : "No");
   6: }

输出结果:

   1: Service porxy is a transparent proxy? Yes.

既然服务代理是一个透明代理,它一定对应了具体的真实代理(RealProxy)。实际上,服务代理对象内部具有一个类型为ServiceChannelProxy的对象作为其真实代理对象。ServiceChannelProxy是WCF中的一个继承自RealProxy的类型,而其核心则是一个类型为ServiceChannel的对象。ServiceChannelProxy和ServiceChannel均是定义在System.ServiceModel.Channels命名空间下的内部(Internal)类型

当我们使用ChannelFactory<TChannel>创建一个服务代理的时候,WCF会根据代表客户端运行时的ClientRuntime创建一个ServiceChannel对象。并且调用之前创建的信道工厂栈并最终创建信道栈。由于ServiceChannel同时引用着代表服务模型层核心的ClientRuntime和信道层的信道栈,所以我们可以说ServiceChannel是连接WCF客户端服务模型层与信道层之间的纽带。当ServiceChannel被成功创建后,WCF会基于该对象创建ServiceChannelProxy对象。最然返回这个真实代理对象的透明代理。

当我们通过显式(将服务代理对象转换成ICommunicationObject类型,并显式调用其Open方法)或者隐式(如果服务代理在未开启的状态下被用于服务调用,在进行服务调用之前会被隐式地开启)开启时,整个信道栈会被开启。下图揭示了服务代理(透明代理)、ServiceChannelProxy(真实代理)、ServiceChannel、ClientRuntime和信道栈之间的关系。

二、服务调用的流程

由于服务代理是一个透明代理,所以针对它的任何一个方法调用都会最终转换到对其真实代理(ServiceChannelProxy)的Invoke方法的调用。所以ServiceChannelProxy会接管所有针对于服务代理对象的服务调用,并最终将调用递交给内部的ServiceChannel处理。

接下来,我们来简单地介绍一下针对一次简单的针对服务代理的服务调用,ServiceChannel在其内部是按照怎样的流程来处理的。实际上,相同的内容已经出现在了《WCF技术剖析(卷1)》第8章《客户端(Client)》中。下面的列表体现了ServiceChannel进行服务调用的整个流程(以请求/回复消息交换模式为例)。

操作选择

如果当前ClientRuntime的OperationSelector属性具有一个操作选择器,则调用其SelectOperation方法或者针对当前服务调用的客户端操作;

输入参数检验

遍历当前ClientRuntime的ParameterInspectors属性表示的参数检验器列表,调用其BeforeCall方法对输入参数实施检验;

序列化请求消息

通过当前ClientOperation的SerializeRequest属性判断是否需要进行请求消息的序列化。如果需要,则根据当前ClientOperation的Formatter属性获取消息格式化器,最终调用SerializeRequest方法将以方法调用形式体现的服务调用序列化成请求消息。

请求消息检验

遍历以当前ClientOperation的MessageInspectors属性表示的消息检验器列表,并调用BeforeSendRequest方法对请求消息实施发送前的检验。

请求消息的发送和回复消息的接收

将请求消息递交给信道层进行进一步处理,经过编码后的请求消息通过传输信道发送到服务端并等待回复。当回复消息抵达客户端后,信道层对其进行接收、解码相应的处理。

回复消息的检验

遍历以当前ClientOperation的MessageInspectors属性表示的消息检验器列表,并调用AfterReceiveReply方法对回复消息实施发送前的检验。

反序列化回复消息

通过当前ClientOperation的DeserializeReply属性判断是否需要进行回复消息的反序列化。如果需要,则根据当前ClientOperation的Formatter属性获取消息格式化器,最终调用DeserializeReply方法将包含在回复消息的调用结果反序列化成方法调用的返回值或者ref/out参数对象。

检验返回值(或者ref/out参数)

遍历当前ClientRuntime的ParameterInspectors属性表示的参数检验器列表,调用其AfterCall方法对返回值或者ref/out参数对象进行检验。

WCF客户端运行时架构体系详解[上篇]

WCF客户端运行时架构体系详解[下篇]

作者:蒋金楠
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文链接

时间: 2024-07-29 19:13:37

WCF客户端运行时架构体系详解[下篇]的相关文章

WCF客户端运行时架构体系详解[上篇]

客户端调用WCF服务的方式不外乎有两种:其一.通过代码生成工具(比如SvcUtil.exe)导入服务的元数据生成服务代理相关的类型:其二.通过ChannelFactory<TChannel>创建服务代理对象.对于前者,生成的服务代理是一个继承自ClientBase<TChannel>的类型.对于这样一个服务代理对象,其内部本质上还是借助于ChannelFactory<TChannel>创建真正用于进行服务调用的代理对象.对于WCF客户端应用编程接口来说,ChannelF

WCF服务端运行时架构体系详解[下篇]

作为WCF中一个核心概念,终结点在不同的语境中实际上指代不同的对象.站在服务描述的角度,我们所说的终结点实际上是指ServiceEndpoint对象.如果站在WCF服务端运行时框架来说,终结点实际上指代的是终结点分发器(EndpointDispatcher).而ServiceEndpoint与EndpointDispatcher是一一匹配的,并且前者是创建后者的基础.而终结点分发器具有自己的运行,即分发运行时(DispatchRuntime). 目录 一.终结点分发器(EndpointDispa

WCF服务端运行时架构体系详解[上篇]

WCF的服务端架构体系又可以成为服务寄宿端架构体系.我们知道,对于一个基于某种类型的服务进行寄宿只需要使用到一个唯一的对象,那就是ServiceHost.甚至在某种语境下,我们所说的服务实际上就是指的对应的ServiceHost对象.整个服务寄宿过程包括两个阶段,即服务描述的创建和服务端运行框架的建立.而第一个阶段创建的服务描述是为了第二个阶段对服务端运行时框架建立服务的,所以我们有必要在对服务描述进行简单的介绍. 目录: 一.从服务描述(Service Description)谈起 二.服务端

WCF服务端运行时架构体系详解[续篇]

终结点分发器在自己的运行时中对请求消息的处理最终肯定体现在相应操作的执行.如果从服务描述的角度来看,操作是一个OperationDescription对象.而服务端分发运行时中的操作则代表的是一个DispatchOperation对象.作为服务描述的一部分,服务所有终结点的所有操作描述(OperationDescription)在ServiceHost创建过程中被创建.而当ServiceHost被正常开始时,这些操作描述最终转换成分发操作(DispatchOperation).而Dispatch

WCF服务端运行时架构体系详解[中篇]

在这篇文章中,我们对信道分发器本身作一个深入的了解,首先来看看它具有哪些可供扩展的组件,以及我们可以针对信道分发器对WCF实现哪些可能的扩展. 目录: ErrorHandler & ServiceThrottle ChannelInitializer IncludeExceptionDetailInFaults ManualAddressing MaxPendingReceives ReceiveSynchronously IsTransactedReceive & MaxTransact

ASP.NET HTTP运行时组成的详解

asp.net|详解 简介 不管使用哪种底层平台,可靠性和性能都是对所有 Web 应用程序的主要要求,尽管从某种意义上讲,这两个要求是相互矛盾的.例如,要构建更可靠.更健壮的应用程序,可能需要将 Web 服务器与具体的应用程序分离,使应用程序在进程外工作.但是,如果在不同于 Web 服务器进程的内存环境中工作,应用程序将变慢.因此,需要采取合理的措施,以确保进程外代码尽可能快地运行. 在构建 Microsoft? ASP.NET 运行时环境时,依据的设计原则即:充分考虑可靠性和性能.得到的 AS

C++:RTTI(RunTime Type Information)运行时类型信息 详解

RTTI, RunTime Type Information, 运行时类型信息, 是多态的主要组成部分, 通过运行时(runtime)确定使用的类型, 执行不同的函数,复用(reuse)接口. dynamic_cast<>可以 使基类指针转换为派生类的指针, 通过判断指针的类型, 可以决定使用的函数. typeid(), 可以判断类型信息, 判断指针指向位置, 在多态中, 可以判断基类还是派生类. 代码: /* * test.cpp * * Created on: 2014.04.22 * A

java程序运行时内存分配详解_java

一. 基本概念    每运行一个java程序会产生一个java进程,每个java进程可能包含一个或者多个线程,每一个Java进程对应唯一一个JVM实例,每一个JVM实例唯一对应一个堆,每一个线程有一个自己私有的栈.进程所创建的所有类的实例(也就是对象)或数组(指的是数组的本身,不是引用)都放在堆中,并由该进程所有的线程共享.Java中分配堆内存是自动初始化的,即为一个对象分配内存的时候,会初始化这个对象中变量.虽然Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在栈中分配,也

[WCF权限控制]WCF自定义授权体系详解[实例篇]

在<原理篇>中,我们谈到WCF自定义授权体系具有两个核心的组件:AuthorizationPolicy和ServiceAuthorizationManager,已经它们是如何写作最终提供一种基于声明的授权实现.为了让自定义授权有深刻的理解,我们来进行一个简单实例来演示如何通过自定义这两个组件实现"非角色授权策略".[源代码从这里下载] 目录: 一.创建演示程序解决方案 二.自定义AuthorizationPolicy 三.自定义ServiceAuthorizationMan