首页 > 代码库 > WCF框架处理流程初探

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 = http://www.mamicode.com/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框架处理流程初探