拜读了大牛蒋金楠的《WCF技术剖析之一:通过一个ASP.NET程序模拟WCF基础架构》,写点心得。

(原文:http://www.cnblogs.com/artech/archive/2009/06/18/1506163.html#!comments)

首先需要理解的是WCF的大致处理流程,设计到了哪些主要的类。下面的图片很好的诠释了处理流程。

代码上,作者在客户端和服务端分别创建了需要用来编码的Encoder和用来序列化/反序列化的DispatchFormatter,实际用到的类是DataContractSerializerOperationFormatter(看名字大概知道它是用来处理datacontract里的operationcontract,即方法的序列化/反序列化),并且建立了servicecontract的operationname/action name到相应的DispatchFormatter的字典,相当于客户端和服务端的约定。

结合代码一个个来看,首先看服务端:

1.接受request,然后Encoder对象会对request进行读取,解码,得到一个Message对象,Message的MessageHeaders包含一个重要的属性Action,后面会用到。

Message request = encoderFactory.Encoder.ReadMessage(this.Request.InputStream,
int.MaxValue, "application/soap+xml;charset=utf-8");

2.接下来是反序列化,服务端要知道客户端想使用哪个service,哪个方法,传了什么参数,需要返回什么参数,返回什么结果。这些通过action可以得到,有了action,就能知道客户要调哪个method,要调哪个DispatchFormatter去反序列化。

            string action = request.Headers.Action;
MethodInfo method = methods[action];
int outArgsCount = ;
foreach (var parameter in method.GetParameters())
{
if (parameter.IsOut) { outArgsCount++; }
}
int inputArgsCount = method.GetParameters().Length - outArgsCount;
object[] parameters = new object[inputArgsCount];
try
{
dispatchFormatters[action].DeserializeRequest(request, parameters);
}
catch
{
}

3.DispatcherFormatter反序列化之后,应该是要create相应的service、method,传入parameter,然后invoke.这里action再次用来关联对应的DispatchFormatter和operationInvokers,但是对于serviceInstance,作者固定了是CalculatorService,不知实际情况是不是也来自于Message.

object serviceInstance = Activator.CreateInstance(typeof(CalculatorService));
object result = operationInvokers[action].Invoke(serviceInstance, parameters, out outArgs);
Message reply = dispatchFormatters[action].SerializeReply(messageversion, outArgs, result);

4.执行完了operation之后,接下来要返回给客户端了,上一步,operation invoke的时候,把返回值,out parameter都序列化起来,也得到一个Message对象,

这个时候再调用Encoder进行编码,传递给Response.

 this.Response.ClearContent();
this.Response.ContentEncoding = Encoding.UTF8;
this.Response.ContentType = "application/soap+xml; charset=utf-8";
encoderFactory.Encoder.WriteMessage(reply, this.Response.OutputStream);
this.Response.Flush();

服务端的任务大致是:从request流中Read(解码)出Message对象,Mesage对象包含了丰富的信息,服务端可以找到要请求的service,method,传入参数,要返回的类型,out参数等,然后DispatchFormatter进行反序列化,动态创建和执行,完了返回Message对象,Encoder再进行Write(编码到outputstream),然后返回。

再来看客户端代码:

客户端同样也会先创建好encoder, DispatchFormatter等,并且把operation name/action name做好字典关联。

1.客户端通过RealProxy的GetTransparentProxy()来返回servicecontract对象(这个不太明白?)

ICalculator calculator = SerivceProxyFactory<ICalculator>.Create(
MessageVersion.Default,
new Uri("http://localhost/Artech.WcfFrameworkSimulator/Calculator.aspx")); public static T Create(MessageVersion messageVersion,Uri remoteAddress)
{
MessageEncoderFactory encoderFactory;
IDictionary<string, IClientMessageFormatter> clientFormatters;
IDictionary<string, IDispatchMessageFormatter> dispatchFormatters;
IDictionary<string, IOperationInvoker> operationInvokers;
IDictionary<string, MethodInfo> methods;
Utility.Create<T>(out encoderFactory,out clientFormatters,out dispatchFormatters,out operationInvokers,out methods);
ServiceRealProxy<T> realProxy = new ServiceRealProxy<T>(messageVersion, remoteAddress, clientFormatters, encoderFactory);
return (T) realProxy.GetTransparentProxy();
}

2.然后重写了RealProxy的Invoke方法来模拟wcf框架客户端做的一系列事情,下面这句话重要,当第2句执行时,第1句的methodCall得到调用的operationcontract,后面的都基于此发生。

 IMethodCallMessage methodCall = (IMethodCallMessage)msg;

double result = calculator.Add(, );

3. 得到operationcontractattribute, 序列化消息,添加ws-address报头,编码等。

OperationContractAttribute attribute = (OperationContractAttribute)attributes[];
string operationName = string.IsNullOrEmpty(attribute.Name) ? methodCall.MethodName : attribute.Name; //序列化请求消息
Message requestMessage = this._messageFormatters[operationName].SerializeRequest(this._messageVersion, methodCall.InArgs); //添加必要的WS-Address报头
EndpointAddress address = new EndpointAddress(this._remoteAddress);
requestMessage.Headers.MessageId = new UniqueId(Guid.NewGuid());
requestMessage.Headers.ReplyTo = new EndpointAddress("http://www.w3.org/2005/08/addressing/anonymous");
address.ApplyTo(requestMessage); //对请求消息进行编码,并将编码生成的字节发送通过HttpWebRequest向服务端发送
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(this._remoteAddress);
webRequest.Method = "Post";
webRequest.KeepAlive = true;
webRequest.ContentType = "application/soap+xml; charset=utf-8";
ArraySegment<byte> bytes = this._messageEncoderFactory.Encoder.WriteMessage(requestMessage, int.MaxValue, BufferManager.CreateBufferManager(long.MaxValue, int.MaxValue));
webRequest.ContentLength = bytes.Array.Length;
webRequest.GetRequestStream().Write(bytes.Array, , bytes.Array.Length);
webRequest.GetRequestStream().Close();
WebResponse webResponse = webRequest.GetResponse();

4.再然后是得到服务端的response,解码,反序列化,得到返回值和out/ref参数,最终完成调用。

//对HttpResponse进行解码生成回复消息.
Message responseMessage = this._messageEncoderFactory.Encoder.ReadMessage(webResponse.GetResponseStream(), int.MaxValue); //回复消息进行反列化生成相应的对象,并映射为方法调用的返回值或者ref/out参数
object[] allArgs = (object[])Array.CreateInstance(typeof(object), methodCall.ArgCount);
Array.Copy(methodCall.Args, allArgs, methodCall.ArgCount);
object[] refOutParameters = new object[GetRefOutParameterCount(methodCall.MethodBase)];
object returnValue = this._messageFormatters[operationName].DeserializeReply(responseMessage, refOutParameters);
MapRefOutParameter(methodCall.MethodBase, allArgs, refOutParameters); //通过ReturnMessage的形式将返回值和ref/out参数返回
return new ReturnMessage(returnValue, allArgs, allArgs.Length, methodCall.LogicalCallContext, methodCall);

WCF框架处理流程初探的更多相关文章

  1. 【WCF 2】理解WCF框架的简单小实例

    导读:上篇博客介绍了WCF框架的整体情况,然后,闲着没事儿,自己做了一个及其简单的WCF框架的例子帮助自己理解.从简单的入手,一步一步深入!本篇博客是介绍怎么用VS2012从头创建一个WCF项目,是一 ...

  2. [老老实实学WCF] 第四篇 初探通信--ChannelFactory

    老老实实学WCF 第四篇 初探通信--ChannelFactory 通过前几篇的学习,我们简单了解了WCF的服务端-客户端模型,可以建立一个简单的WCF通信程序,并且可以把我们的服务寄宿在IIS中了. ...

  3. redis源码学习之工作流程初探

    目录 背景 环境准备 下载redis源码 下载Visual Studio Visual Studio打开redis源码 启动过程分析 调用关系图 事件循环分析 工作模型 代码分析 动画演示 网络模块 ...

  4. struts2 框架处理流程

    struts2 框架处理流程 流程图如下: 注意:StrutsPrepareAndExecuteFilter替代了2.1.3以前的FilterDispatcher过滤器,使得在执行Action之前可以 ...

  5. WCF 框架运行时类图

    本文画出了 WCF 框架运行时的重点类之间的类关系图. Binding 一个 Binding 由多个 BindingElement 组成.BindingElement 作为主要的扩展点.每一个 Bin ...

  6. SSH(Struts2+Spring+Hibernate)框架搭建流程<注解的方式创建Bean>

    此篇讲的是MyEclipse9工具提供的支持搭建自加包有代码也是相同:用户登录与注册的例子,表字段只有name,password. SSH,xml方式搭建文章链接地址:http://www.cnblo ...

  7. 【WCF 1】WCF框架宏观了解

    导读:使用WCF框架爱开发项目也有很长一段时间了,最开始的时候,是理解的不深,所以不写博客进行总结.后来是项目赶,发现需要总结的有很多,一直没有把WCF排上日程,尤其是最近研究EF这一块,更是研究了一 ...

  8. OpenCart框架运行流程介绍

    框架运行流程介绍 这样的一个get请求http://hostname/index.php?route=common/home 发生了什么? 1. 开始执行入口文件index.php. 2. requi ...

  9. J2EE进阶(六)SSH框架工作流程项目整合实例讲解

    J2EE进阶(六)SSH框架工作流程项目整合实例讲解 请求流程 经过实际项目的进行,结合三大框架各自的运行机理可分析得出SSH整合框架的大致工作流程. 首先查看一下客户端的请求信息: 对于一个Web项 ...

随机推荐

  1. 模仿console自写函数打印js的对象

    本以为写个递归函数就可以将js的对象打印出来. 当然第一个想到的估计是JSON.stringify() 这个函数.但这个函数打印到浏览器 显示效果不友好.最友好的显示肯定是 控制台打印咯. 结果尝试打 ...

  2. nwjs 配置文件package.json 转载

    配置文件package.json nw在启动应用程序时,首先要读取package.json文件,初始化基本属性,下面我们看看package.json的完整参数.每个参数配置都标有注释. { /**指定 ...

  3. Atom安装activate-power-mode插件(震动炫酷)

    1.下载安装Atom,地址:https://atom.io/ 2.下载安装activate-power-mode插件,地址:https://github.com/JoelBesada/activate ...

  4. C# 多线程详解 Part.04(Lock、Monitor、生产与消费)

           系列1 曾经说过:每个线程都有自己的资源,但代码区是共享的,即每个线程都可以执行相同的函数.        这可能带来的问题就是多个线程同时执行一个函数,并修改同一变量值,这将导致数据的 ...

  5. .NET设计规范————命名规范

    NET设计规范:约定.惯用法与模式———命名规范 前言:          最近在看<.NET设计规范:约定.惯用法与模式>一书,主要还是讲.NET的设计规范,以前对这一块也不是特别在意, ...

  6. python中import和from...import区别

    在python用import或者from...import来导入相应的模块.模块其实就是一些函数和类的集合文件,它能实现一些相应的功能,当我们需要使用这些功能的时候,直接把相应的模块导入到我们的程序中 ...

  7. [2015.08.13]万峰快递单打印软件 v2.2

    <万峰快递单打印软件>是一款简单易用,且支持所有快递单的打印软件.1.支持文字打印位置的坐标精确定位和微调的打印工具.2.操作灵活,只需录入收件人和发件人信息即可打印:3.快递单打印尺寸和 ...

  8. 提供VR定制开发、AR定制开发(VR游戏定制、应用定制)

    设置输出路径 添加烘培输出的贴图类型 添加“LightingMap”类型 设置烘培贴图大小和目标贴图位置为“自发光” 设置烘培材质,选择“输出到源” 点击“渲染”即可 24.标准材质贴图的烘培光影处理 ...

  9. STM32固件库3.5+uCOS2.86移植(转自暴走的工程师)

    考了很多移植的资料和代码,终于移植好了...应该是完美移植吧~~哈哈哈~~ 编译环境是IAR 工程适用于STM32F10X大容量产品,如果不是,请自行修改启动文件和工程配置 编译器优化等级最高...这 ...

  10. Java的动态绑定机制

    Java的动态绑定又称为运行时绑定.意思就是说,程序会在运行的时候自动选择调用哪儿个方法. 一.动态绑定的过程: 例子: public class Son extends Father Son son ...