WCF框架处理流程初探

拜读了大牛蒋金楠的《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 = 0;
            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(1, 2);

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

OperationContractAttribute attribute = (OperationContractAttribute)attributes[0];
            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, 0, 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);
时间: 2024-11-09 17:52:29

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

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

原文:[老老实实学WCF] 第四篇 初探通信--ChannelFactory 老老实实学WCF 第四篇 初探通信--ChannelFactory 通过前几篇的学习,我们简单了解了WCF的服务端-客户端模型,可以建立一个简单的WCF通信程序,并且可以把我们的服务寄宿在IIS中了.我们不禁感叹WCF模型的简单,寥寥数行代码和配置,就可以把通信建立起来.然而,仔细品味一下,这里面仍有许多疑点:服务器是如何建起服务的?我们在客户端调用一个操作后发生了什么?元数据到底是什么东西?等等.我们现在对WCF的理

(转)[老老实实学WCF] 第四篇 初探通信--ChannelFactory

第四篇 初探通信--ChannelFactory 通过前几篇的学习,我们简单了解了WCF的服务端-客户端模型,可以建立一个简单的WCF通信程序,并且可以把我们的服务寄宿在IIS中了.我们不禁感叹WCF模型的简单,寥寥数行代码和配置,就可以把通信建立起来.然而,仔细品味一下,这里面仍有许多疑点:服务器是如何建起服务的?我们在客户端调用一个操作后发生了什么?元数据到底是什么东西?等等.我们现在对WCF的理解应该还处于初级阶段,我们就会觉得有许多这样的谜团了. 虽然我们生活在WCF为我们构建的美好的应

SSH(Struts2+Spring+Hibernate)框架搭建流程&lt;注解的方式创建Bean&gt;

此篇讲的是MyEclipse9工具提供的支持搭建自加包有代码也是相同:用户登录与注册的例子,表字段只有name,password. SSH,xml方式搭建文章链接地址:http://www.cnblogs.com/wkrbky/p/5912810.html 一.Hibernate(数据层)的搭建: 实现流程 二.Spring(注入实例)的使用: 实现流程 三.Struts2(MVC)的搭建: 实现流程 这里注意一点问题: Struts2与Hibernate在一起搭建,antlr包,有冲突.MyE

Python Web框架之Django初探(一)

Python Web框架之Django初探 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的框架模式,即模型M,视图V和控制器C.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件.并于2005年7月在BSD许可证下发布.这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的. Django可以运行在Apache,Nginx上,也可以运行在支持WSGI,FastCGI的服务器上.支持多种数据

struts2 框架处理流程

struts2 框架处理流程 流程图如下: -->FilterDispatcher过滤器在2.1.3以后被StrutsPrepareAndExecuteFilter所替代,使得在执行Action之前可以添加过滤器了: -->客户端初始化一个指向servlet容器的request请求,请求经过一系列的过滤器,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用某个Action. 1)Struts2框架的大致处理流程: ①     浏览器发出请求,例如请求/log

图文解析Struts2框架执行流程

struts的架构图 (1)提交请求 客户端通过HttpServletRequest向servlet容器(即tomcat)提交一个请求. 请求经过一系列的过滤器,例如图中的ActionContextCleanUp和Other filter(SlterMesh,etc)等,最后被struts的核心过滤器FilterDispatcher控制到. 注:核心控制器2.1.3版本之后,struts的filterDispatcher核心控制器变成了StrutsPrepareAndExecuteFilte,如

【Nginx】事件驱动框架处理流程

ngx_event_core_module模块的ngx_event_process_init方法对事件模块做了一些初始化.其中包括将"请求连接"这样一个读事件对应的处理方法(handler)设置为ngx_event_accept函数,并将此事件添加到epoll模块中.当有新连接事件发生时,ngx_event_accept就会被调用.大致流程是这样: worker进程在ngx_worker_process_cycle方法中不断循环调用ngx_process_events_and_time

让你提前认识软件开发(37):研发流程初探

第3部分 软件研发工作总结 研发流程初探         (本文是我到公司一个月后对于工作的一些感想,欢迎阅读.) 到公司实习已经有一个多月了,最近我完成了第一个正式任务.回想起来,那个过程充满挫折,也充满了惊喜.虽然不像一般电影那样一波三折,但也是有让人很难忘记的地方.在这篇文章中,我对整个过程进行一个简单的描述,同时偶尔也发表一下个人的一点感慨. 整个过程包括如图1所示的6个步骤. 图1 软件开发流程         (1) 接受需求 一般说来,对于刚入职不久的员工,项目组不会布置太复杂的任

spring mvc控制框架的流程及原理1: 总概及源码分析

主要介绍spring mvc控制框架的流程及原理 Spring Web MVC处理请求的流程 具体执行步骤如下: 首先用户发送请求————>前端控制器,前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分:图2-1中的1.2步骤: 页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,这个对象在Spring Web MVC中叫命令对象,并进行验证,然后将命令对象委托给业务对象进行处理:处理完毕后返回一个Model