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