自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

通過(guò)一個(gè)ASP.NET程序模擬WCF基本架構(gòu)

開(kāi)發(fā) 后端
本文對(duì)WCF的基本架構(gòu)作了一個(gè)大致的講解。與傳統(tǒng)的對(duì)WCF的工作流程進(jìn)行平鋪直敘不同,本文將借助于我們熟悉的ASP.NET作為請(qǐng)求處理平臺(tái),通過(guò)一個(gè)簡(jiǎn)單的托管程序模擬整個(gè)WCF客戶端和服務(wù)端的架構(gòu)。

在《WCF技術(shù)剖析》寫(xiě)作期間,對(duì)WCF又有了新的感悟,為此以書(shū)名開(kāi)始本人的第三個(gè)WCF系列。本系列的目的在于對(duì)《WCF技術(shù)剖析》的補(bǔ)充,會(huì)對(duì)書(shū)中的一些內(nèi)容進(jìn)行展開(kāi)講述,同時(shí)會(huì)囊括很多由于篇幅的原因忍痛割棄的內(nèi)容。

本系列的第一篇,我將會(huì)對(duì)WCF的基本架構(gòu)作一個(gè)大致的講解。不過(guò),一改傳統(tǒng)對(duì)WCF的工作流程進(jìn)行平鋪直敘,我將另辟蹊徑,借助于我們熟悉的ASP.NET作為請(qǐng)求處理平臺(tái),通過(guò)一個(gè)簡(jiǎn)單的托管程序模擬整個(gè)WCF客戶端和服務(wù)端的架構(gòu)。本篇文章的大部分內(nèi)容節(jié)選自《WCF技術(shù)剖析(卷1)》第八章。

WCF框架處理流程和涉及的組件

我們的模擬程序?qū)⒛愦罱ㄒ粋€(gè)迷你版的WCF框架,為了展示W(wǎng)CF整個(gè)處理流程中使用到一些特殊組件。我們首先來(lái)簡(jiǎn)單介紹一下對(duì)于一個(gè)簡(jiǎn)單的WCF服務(wù)調(diào)用,WCF的客戶端和服務(wù)端框架的處理流程,和該流程的每一個(gè)階段都使用那些重要組件。

下面的列表列出了WCF服務(wù)端框架對(duì)于處理一個(gè)簡(jiǎn)單的WCF服務(wù)調(diào)用請(qǐng)求所提供的功能,以及相應(yīng)的功能承載的組件:

請(qǐng)求消息的接收和回復(fù)消息的發(fā)送:服務(wù)端在傳輸層監(jiān)聽(tīng)與接收來(lái)自客戶的請(qǐng)求,并將經(jīng)過(guò)編碼后的回復(fù)消息通過(guò)傳輸層發(fā)送到客戶端

請(qǐng)求消息的解碼和回復(fù)消息的編碼:將接收到的字節(jié)數(shù)組通過(guò)解碼生成請(qǐng)求消息對(duì)象,并將回復(fù)消息通過(guò)編程轉(zhuǎn)化成字節(jié)組。消息的編碼和解碼通過(guò)MessageEncoder完成,而MessageEncoderFactory負(fù)責(zé)創(chuàng)建該對(duì)象

請(qǐng)求消息的反序列化和回復(fù)消息的序列化:對(duì)請(qǐng)求消息進(jìn)行反序列化,為服務(wù)操作的執(zhí)行生成相應(yīng)的輸入?yún)?shù),以及將服務(wù)操作執(zhí)行的結(jié)果(返回值或者ref/out參數(shù))序列化,并生成回復(fù)消息。序列化和反序列化通過(guò)DispatchMessageFormatter完成

服務(wù)對(duì)象的創(chuàng)建:創(chuàng)建或者激活服務(wù)對(duì)象實(shí)例,IntanceProvider用于服務(wù)對(duì)象的創(chuàng)建或獲取

服務(wù)操作的執(zhí)行:調(diào)用創(chuàng)建的服務(wù)對(duì)象的操作方法,并傳入經(jīng)過(guò)反序列化生成的輸入?yún)?shù)。OperationInvoker完成對(duì)服務(wù)操作的最終執(zhí)行

較之服務(wù)端的流程,客戶端的流程顯得相對(duì)簡(jiǎn)單,僅僅包含以下三個(gè)必需的階段:

請(qǐng)求消息的序列化和回復(fù)消息的反序列化:生成請(qǐng)求消息并將輸入?yún)?shù)序列化到請(qǐng)求消息中,以及對(duì)回復(fù)消息進(jìn)行反序列化,轉(zhuǎn)化成方法調(diào)用的返回值或者ref/out參數(shù)。序列化和反序列化通過(guò)ClienthMessageFormatter完成

請(qǐng)求消息的編碼和回復(fù)消息的解碼:對(duì)請(qǐng)求消息進(jìn)行編碼生成字節(jié)數(shù)組供傳輸層發(fā)送,以及將傳輸層接收到的字節(jié)數(shù)組解碼生成恢復(fù)消息。消息的編碼和解碼通過(guò)MessageEncoder完成,而MessageEncoderFactory負(fù)責(zé)創(chuàng)建該對(duì)象

請(qǐng)求消息的發(fā)送和回復(fù)消息的接收:在傳輸層將經(jīng)過(guò)編碼的請(qǐng)求消息發(fā)送到服務(wù)端,以及將接收來(lái)自服務(wù)端的恢復(fù)消息

 精簡(jiǎn)版WCF客戶端與服務(wù)端組件 
圖1 精簡(jiǎn)版WCF客戶端與服務(wù)端組件

圖1反映了進(jìn)行服務(wù)調(diào)用的必要步驟和使用到的相關(guān)WCF組件。在本案例演示中,我們需要做的就是手工創(chuàng)建這些組件,并通過(guò)我們自己的代碼利用它們搭建一個(gè)建議版的WCF框架。如果讀者能夠?qū)Ρ景咐膶?shí)現(xiàn)有一個(gè)清晰的理解,相信對(duì)于整個(gè)WCF的框架就不會(huì)感到陌生了。

圖2顯示了本案例解決方案的基本結(jié)構(gòu),總共分三個(gè)項(xiàng)目。Contracts用于定義服務(wù)契約,被服務(wù)端和客戶端引用??蛻舳送ㄟ^(guò)一個(gè)Console應(yīng)用模擬,而服務(wù)端則通過(guò)一個(gè)ASP.NET Website實(shí)現(xiàn)。

WCF框架模擬案例應(yīng)用結(jié)構(gòu) 
圖2 WCF框架模擬案例應(yīng)用結(jié)構(gòu)

#p#

步驟一、通過(guò)服務(wù)契約類型創(chuàng)建相關(guān)組件

WCF在整個(gè)服務(wù)調(diào)用生命周期的不同階段,會(huì)使用到不同的組件。我們通過(guò)一個(gè)方法將服務(wù)端和客戶端所需的所有組件都創(chuàng)建出來(lái),為此,我們?cè)贑ontracts項(xiàng)目中添加了一個(gè)Utility類型,在Create< T>方法中創(chuàng)建所有的組件并通過(guò)輸出參數(shù)的形式返回,泛型類型T表示的是服務(wù)契約類型。在該方法中,輸出參數(shù)encoderFactory被服務(wù)端和客戶端用于消息的編碼和解碼,clientFormatters和dispatchFormatters以字典的形式包含了基于服務(wù)操作的IClientMessageFormatter和IDispatchMessageFormatter,其中clientFormatters和dispatchFormatters的Key分別為操作名稱和操作對(duì)應(yīng)的Action。同樣通過(guò)字典形式返回的operationInvokers和methods用于在服務(wù)端執(zhí)行相應(yīng)的操作方法,Key同樣為操作對(duì)應(yīng)的Action。

  1. public static class Utility  
  2. {  
  3.     public static void Create< T>(out MessageEncoderFactory encoderFactory,  
  4.         out IDictionary< string, IClientMessageFormatter> clientFormatters,  
  5.         out IDictionary< string, IDispatchMessageFormatter> dispatchFormatters,  
  6.         out IDictionary< string, IOperationInvoker> operationInvokers,  
  7.         out IDictionary< string, MethodInfo> methods)  
  8.     {  
  9.         //省略實(shí)現(xiàn)  
  10.     }  

具體的實(shí)現(xiàn)如下,由于在WCF框架中使用的MessageEncoderFactory(TextMessageEncoderFactory)、MessageFormatter(DataContractSerializerOperationFormatter)和OperationInvoker(SyncMethodInvoker)都是一些內(nèi)部類型,所以只能通過(guò)反射的方式創(chuàng)建它們。而操作名稱和Action也主要通過(guò)反射的原理解析應(yīng)用在服務(wù)方法上的OperationContractAttribute得到。

  1. public static void Create< T>(out MessageEncoderFactory encoderFactory,  
  2.     out IDictionary< string, IClientMessageFormatter> clientFormatters,  
  3.     out IDictionary< string, IDispatchMessageFormatter> dispatchFormatters,  
  4.     out IDictionary< string, IOperationInvoker> operationInvokers,  
  5.     out IDictionary< string, MethodInfo> methods)  
  6. {  
  7.     //確保類型T是應(yīng)用了ServiceContractAttribute的服務(wù)契約  
  8.     object[] attributes = typeof(T).GetCustomAttributes(typeof(ServiceContractAttribute), false);  
  9.     if (attributes.Length == 0)  
  10.     {  
  11.         throw new InvalidOperationException(string.Format("The type \"{0}\" is not a ServiceContract!", typeof(T).AssemblyQualifiedName));  
  12.     }   
  13.  
  14.     //創(chuàng)建字典保存IClientMessageFormatter、IDispatchMessageFormatter、IOperationInvoker和MethodInfo  
  15.     clientFormatters = new Dictionary< string, IClientMessageFormatter>();  
  16.     dispatchFormatters = new Dictionary< string, IDispatchMessageFormatter>();  
  17.     operationInvokers = new Dictionary< string, IOperationInvoker>();  
  18.     methods = new Dictionary< string, MethodInfo>();   
  19.  
  20.     //MessageEncoderFactory  
  21.     string encoderFactoryType = "System.ServiceModel.Channels.TextMessageEncoderFactory,System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";  
  22.     encoderFactory = (MessageEncoderFactory)Activator.CreateInstance(Type.GetType(encoderFactoryType), MessageVersion.Default, Encoding.UTF8, int.MaxValue, int.MaxValue, new XmlDictionaryReaderQuotas());   
  23.  
  24. //得到OperationDecription列表  
  25. string defaultNamespace = "http://tempuri.org/";  
  26.     ServiceContractAttribute serviceAttribute = (ServiceContractAttribute)attributes[0];  
  27.     string serviceNamepace = string.IsNullOrEmpty(serviceAttribute.Namespace) ? defaultNamespace : serviceAttribute.Namespace;  
  28.     string serviceName = string.IsNullOrEmpty(serviceAttribute.Name) ? typeof(T).Name : serviceAttribute.Name;  
  29.     var operations = ContractDescription.GetContract(typeof(T)).Operations;   
  30.  
  31.     //得到具體的IClientMessageFormatter、IDispatchMessageFormatter和IOperationInvoker的具體類型  
  32.     //IClientMessageFormatter+IDispatchMessageFormatter:DataContractSerializerOperationFormatter  
  33.     //IOperationInvoker:SyncMethodInvoker  
  34.     string formatterTypeName = "System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter,System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";  
  35.     Type formatterType = Type.GetType(formatterTypeName);  
  36.     ConstructorInfo formatterConstructor = formatterType.GetConstructor(new Type[] { typeof(OperationDescription), typeof(DataContractFormatAttribute), typeof(DataContractSerializerOperationBehavior) });  
  37.     string operationInvokerTypeName = "System.ServiceModel.Dispatcher.SyncMethodInvoker,System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";  
  38.     Type operationInvokerType = Type.GetType(operationInvokerTypeName);   
  39.  
  40.     foreach (MethodInfo method in typeof(T).GetMethods())  
  41.     {  
  42.         attributes = method.GetCustomAttributes(typeof(OperationContractAttribute), true);  
  43.         if (attributes.Length > 0)  
  44.         {  
  45.             OperationContractAttribute operationAttribute = (OperationContractAttribute)attributes[0];  
  46.             string operationName = string.IsNullOrEmpty(operationAttribute.Name) ? method.Name : operationAttribute.Name;  
  47.             //通過(guò)OperationContractAttribute得到Action  
  48.             string action;  
  49.             if (string.IsNullOrEmpty(operationAttribute.Action))  
  50.             {  
  51.                 action = string.Format("{0}{1}/{2}", serviceNamepace, serviceName, operationName);  
  52.             }  
  53.             else 
  54.             {  
  55.                 action = operationAttribute.Action;  
  56.             }   
  57.  
  58.             OperationDescription operation = operations.Where(op => op.Name == operationName).ToArray< OperationDescription>()[0];  
  59.             //通過(guò)反射創(chuàng)建DataContractSerializerOperationFormatter對(duì)象  
  60.             object formatter = formatterConstructor.Invoke(new object[] { operation, new DataContractFormatAttribute(), null });  
  61.             clientFormatters.Add(operationName, formatter as IClientMessageFormatter);  
  62.             dispatchFormatters.Add(action, formatter as IDispatchMessageFormatter);   
  63.  
  64.             //通過(guò)反射創(chuàng)建SyncMethodInvoker對(duì)象  
  65.             IOperationInvoker operationInvoker = (IOperationInvoker)Activator.CreateInstance(operationInvokerType, method);  
  66.             operationInvokers.Add(action, operationInvoker);  
  67.             methods.Add(action, method);  
  68.         }  
  69. }  

步驟二、創(chuàng)建服務(wù)契約和實(shí)現(xiàn)服務(wù)

接下來(lái)為本案例創(chuàng)建一個(gè)服務(wù)契約和實(shí)現(xiàn)該契約。服務(wù)契約定義在Contracts項(xiàng)目,具體的服務(wù)實(shí)現(xiàn)在模擬服務(wù)端的ASP.NET Web站點(diǎn)中。簡(jiǎn)單起見(jiàn),依然沿用計(jì)算服務(wù)的例子。

  1. namespace Artech.WcfFrameworkSimulator.Contracts  
  2. {  
  3.     [ServiceContract(Namespace = "http://www.artech.com/")]  
  4.     public interface ICalculator  
  5.     {  
  6.         [OperationContract]  
  7.         double Add(double x, double y);  
  8.     }  
  9. }  
  10.    
  11.  
  12. public class CalculatorService : ICalculator  
  13. {  
  14.     public double Add(double x, double y)  
  15.     {  
  16.         return x + y;  
  17.     }  
  18. }  

#p#

步驟三、實(shí)現(xiàn)服務(wù)端對(duì)服務(wù)調(diào)用請(qǐng)求的處理

我們通過(guò)一個(gè)ASP.NET的Web Page來(lái)模擬WCF服務(wù)端對(duì)服務(wù)請(qǐng)求的處理,下面的Calculator類型相關(guān)的代碼實(shí)際上就是Calculator.aspx的后臺(tái)代碼(Code Behind)。整個(gè)處理流程不算復(fù)雜。在構(gòu)造函數(shù)中,調(diào)用Utility的Create< ICalculator>方法,將所需的組件進(jìn)行初始化,而具體的服務(wù)調(diào)用請(qǐng)求處理的邏輯在直接寫(xiě)在Web Page的Load事件中。

首先,通過(guò)MessageCoderFactory創(chuàng)建MessageEncoder對(duì)接收到的以HttpRequest形式體現(xiàn)的服務(wù)調(diào)用請(qǐng)求進(jìn)行解碼,并生成請(qǐng)求消息。通過(guò)請(qǐng)求消息得到當(dāng)前服務(wù)操作的Action屬性后,在初始化過(guò)程中得到的基于服務(wù)契約所有MethodInfo列表中,根據(jù)該Action得到當(dāng)前操作對(duì)應(yīng)的MethodInfo對(duì)象。借助于MethodInfo對(duì)象得到操作方法的輸入?yún)?shù)和輸出參數(shù)數(shù)量后,創(chuàng)建兩個(gè)對(duì)象數(shù)組,分別用于保存通過(guò)DispatchMessageFormatter對(duì)象對(duì)于請(qǐng)求消息進(jìn)行反序列化得到的輸入?yún)?shù),和通過(guò)OperationInvoker執(zhí)行操作方法得到的輸出參數(shù)。在OperationInvoker執(zhí)行操作方法之前,通過(guò)反射的方式直接創(chuàng)建服務(wù)對(duì)象,這一步在真正的WCF框架中是通過(guò)InstanceProvider實(shí)現(xiàn)的。

通過(guò)OperationInvoker執(zhí)行操作方法的結(jié)果有兩種形式:返回值和輸出參數(shù)(包括引用參數(shù))。它們通過(guò)被傳入DispatchMessageFormatter被序列化并生成回復(fù)消息對(duì)象?;貜?fù)消息通過(guò)MessageCoderFactory創(chuàng)建MessageEncoder進(jìn)行編碼后通過(guò)HttpResponse返回。

  1. public partial class Calculator : System.Web.UI.Page  
  2. {  
  3.     private static MessageVersion messageversion = MessageVersion.Default;  
  4.     private static MessageEncoderFactory encoderFactory;  
  5.     private static IDictionary< string, IDispatchMessageFormatter> dispatchFormatters;  
  6.     private static IDictionary< string, IOperationInvoker> operationInvokers;  
  7.     private static IDictionary< string, MethodInfo> methods;  
  8.  
  9.     protected Calculator()  
  10.     {  
  11.         IDictionary< string, IClientMessageFormatter> clientFormatters;  
  12.         Utility.Create< ICalculator>(out encoderFactory, out clientFormatters, out dispatchFormatters, out operationInvokers, out methods);  
  13.     }  
  14.  
  15.     protected void Page_Load(object sender, EventArgs e)  
  16.     {  
  17.         //對(duì)HttpPRequest進(jìn)行解碼生成請(qǐng)求消息對(duì)象  
  18.         Message request = encoderFactory.Encoder.ReadMessage(this.Request.InputStream, int.MaxValue, "application/soap+xml; charset=utf-8");  
  19.  
  20.         //通過(guò)請(qǐng)求消息得到代表服務(wù)操作的Action  
  21.         string action = request.Headers.Action;  
  22.  
  23.         //通過(guò)Action從MethodInfo字典中獲取服務(wù)操作對(duì)應(yīng)的MethodInfo對(duì)象  
  24.         MethodInfo method = methods[action];  
  25.  
  26.         //得到輸出參數(shù)的數(shù)量  
  27.         int outArgsCount = 0;  
  28.         foreach (var parameter in method.GetParameters())  
  29.         {  
  30.             if (parameter.IsOut)  
  31.             {  
  32.                 outArgsCount++;  
  33.             }  
  34.         }  
  35.  
  36.         //創(chuàng)建數(shù)組容器,用于保存請(qǐng)求消息反序列后生成的輸入?yún)?shù)對(duì)象  
  37.         int inputArgsCount = method.GetParameters().Length - outArgsCount;  
  38.         object[] parameters = new object[inputArgsCount];  
  39.         dispatchFormatters[action].DeserializeRequest(request, parameters);  
  40.  
  41.         List< object> inputArgs = new List< object>();  
  42.         object[] outArgs = new object[outArgsCount];  
  43.         //創(chuàng)建服務(wù)對(duì)象,在WCF中服務(wù)對(duì)象通過(guò)InstanceProvider創(chuàng)建  
  44.         object serviceInstance = Activator.CreateInstance(typeof(CalculatorService));  
  45.         //執(zhí)行服務(wù)操作  
  46.         object result = operationInvokers[action].Invoke(serviceInstance, parameters, out outArgs);  
  47.         //將操作執(zhí)行的結(jié)果(返回值或者輸出參數(shù))序列化生成回復(fù)消息  
  48.         Message reply = dispatchFormatters[action].SerializeReply(messageversion, outArgs, result);  
  49.         this.Response.ClearContent();  
  50.         this.Response.ContentEncoding = Encoding.UTF8;  
  51.         this.Response.ContentType = "application/soap+xml; charset=utf-8";  
  52.         //對(duì)回復(fù)消息進(jìn)行編碼,并將編碼后的消息通過(guò)HttpResponse返回  
  53.         encoderFactory.Encoder.WriteMessage(reply, this.Response.OutputStream);  
  54.         this.Response.Flush();  
  55.     }  
  56. }  

步驟四、實(shí)現(xiàn)客戶端對(duì)服務(wù)調(diào)用請(qǐng)求的處理

由于在客戶端對(duì)服務(wù)請(qǐng)求的處理是通過(guò)一個(gè)RealProxy(ServiceChannelFactory)實(shí)現(xiàn)的,為了真實(shí)模擬WCF處理框架,在這里通過(guò)一個(gè)自定義RealProxy來(lái)實(shí)現(xiàn)客戶端相關(guān)的服務(wù)調(diào)用請(qǐng)求的處理。下面代碼中定義的ServiceRealProxy< IContract>就是這樣一個(gè)自定義RealProxy。

用于處理服務(wù)調(diào)用請(qǐng)求的相關(guān)組件對(duì)象,比如MessageEncoderFactory和IClientMessageFormatter字典,以及所需的屬性,比如消息的版本和服務(wù)的目的地址,通過(guò)構(gòu)造函數(shù)指定。而具體的請(qǐng)求處理實(shí)現(xiàn)在重寫(xiě)的Invoke方法之中。首先通過(guò)解析應(yīng)用在當(dāng)前方法的上面的OperationContractAttribute得到服務(wù)操作的名稱,以此為Key從IClientMessageFormatter字典中得到當(dāng)前服務(wù)操作對(duì)應(yīng)的IClientMessageFormatter對(duì)象。當(dāng)前操作方法調(diào)用的輸入?yún)?shù)通過(guò)IClientMessageFormatter對(duì)象進(jìn)行序列化后生成請(qǐng)求消息。為請(qǐng)求消息添加必要的尋址報(bào)頭后,通過(guò)MessageEncoderFactory創(chuàng)建的MessageEncoder對(duì)請(qǐng)求消息進(jìn)行編碼。經(jīng)過(guò)編碼的消息以HttpRequest的形式發(fā)送到服務(wù)端,從而完成了服務(wù)調(diào)用請(qǐng)求的發(fā)送。

服務(wù)調(diào)用的結(jié)果通過(guò)HttpResponse的形式返回后,先通過(guò)MessageEncoder對(duì)其解碼,并生成回復(fù)消息?;貜?fù)消息通過(guò)IClientMessageFormatter進(jìn)行反序列化后,在消息中以XML InfoSet實(shí)行體現(xiàn)的結(jié)果被轉(zhuǎn)化成具體的對(duì)象,這些對(duì)象被最終影射為方法調(diào)用的返回值和輸出參數(shù)(包含引用參數(shù))。

  1. namespace Artech.WcfFrameworkSimulator.Client  
  2. {  
  3.     public class ServiceRealProxy< IContract> : RealProxy  
  4.     {  
  5.         private Uri _remoteAddress;  
  6.         private IDictionary< string, IClientMessageFormatter> _messageFormatters;  
  7.         private MessageVersion _messageVersion = MessageVersion.Default;  
  8.         private MessageEncoderFactory _messageEncoderFactory;  
  9.  
  10.         public ServiceRealProxy(MessageVersion messageVersion, Uri address, IDictionary< string, IClientMessageFormatter> messageFormaters, MessageEncoderFactory messageEncoderFactory)  
  11.             : base(typeof(IContract))  
  12.         {  
  13.             object[] attribute = typeof(IContract).GetCustomAttributes(typeof(ServiceContractAttribute), false);  
  14.             if (attribute.Length == 0)  
  15.             {  
  16.                 throw new InvalidOperationException(string.Format("The type \"{0}\" is not a ServiceContract!", typeof(IContract).AssemblyQualifiedName));  
  17.             }  
  18.             this._messageVersion = messageVersion;  
  19.             this._remoteAddress = address;  
  20.             this._messageFormatters = messageFormaters;  
  21.             this._messageEncoderFactory = messageEncoderFactory;  
  22.         }  
  23.  
  24.         public override IMessage Invoke(IMessage msg)  
  25.         {  
  26.             IMethodCallMessage methodCall = (IMethodCallMessage)msg;  
  27.  
  28.             //Get Operation name.  
  29.             object[] attributes = methodCall.MethodBase.GetCustomAttributes(typeof(OperationContractAttribute), true);  
  30.             if (attributes.Length == 0)  
  31.             {  
  32.                 throw new InvalidOperationException(string.Format("The method \"{0}\" is not a valid OperationContract.", methodCall.MethodName));  
  33.             }  
  34.             OperationContractAttribute attribute = (OperationContractAttribute)attributes[0];  
  35.             string operationName = string.IsNullOrEmpty(attribute.Name) ? methodCall.MethodName : attribute.Name;  
  36.  
  37.             //序列化請(qǐng)求消息  
  38.             Message requestMessage = this._messageFormatters[operationName].SerializeRequest(this._messageVersion, methodCall.InArgs);  
  39.  
  40.             //添加必要的WS-Address報(bào)頭  
  41.             EndpointAddress address = new EndpointAddress(this._remoteAddress);  
  42.             requestMessage.Headers.MessageId = new UniqueId(Guid.NewGuid());  
  43.             requestMessage.Headers.ReplyTo = new EndpointAddress("http://www.w3.org/2005/08/addressing/anonymous");  
  44.             address.ApplyTo(requestMessage);  
  45.  
  46.             //對(duì)請(qǐng)求消息進(jìn)行編碼,并將編碼生成的字節(jié)發(fā)送通過(guò)HttpWebRequest向服務(wù)端發(fā)送  
  47.             HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(this._remoteAddress);  
  48.             webRequest.Method = "Post";  
  49.             webRequest.KeepAlive = true;  
  50.             webRequest.ContentType = "application/soap+xml; charset=utf-8";  
  51.             ArraySegment< byte> bytes = this._messageEncoderFactory.Encoder.WriteMessage(requestMessage, int.MaxValue, BufferManager.CreateBufferManager(long.MaxValue, int.MaxValue));  
  52.             webRequest.ContentLength = bytes.Array.Length;  
  53.             webRequest.GetRequestStream().Write(bytes.Array, 0, bytes.Array.Length);  
  54.             webRequest.GetRequestStream().Close();  
  55.             WebResponse webResponse = webRequest.GetResponse();  
  56.  
  57.             //對(duì)HttpResponse進(jìn)行解碼生成回復(fù)消息.  
  58.             Message responseMessage = this._messageEncoderFactory.Encoder.ReadMessage(webResponse.GetResponseStream(), int.MaxValue);  
  59.  
  60.             //回復(fù)消息進(jìn)行反列化生成相應(yīng)的對(duì)象,并映射為方法調(diào)用的返回值或者ref/out參數(shù)  
  61.             object[] allArgs = (object[])Array.CreateInstance(typeof(object), methodCall.ArgCount);  
  62.             Array.Copy(methodCall.Args, allArgs, methodCall.ArgCount);  
  63.             object[] refOutParameters = new object[GetRefOutParameterCount(methodCall.MethodBase)];  
  64.             object returnValue = this._messageFormatters[operationName].DeserializeReply(responseMessage, refOutParameters);  
  65.             MapRefOutParameter(methodCall.MethodBase, allArgs, refOutParameters);  
  66.  
  67.             //通過(guò)ReturnMessage的形式將返回值和ref/out參數(shù)返回  
  68.             return new ReturnMessage(returnValue, allArgs, allArgs.Length, methodCall.LogicalCallContext, methodCall);  
  69.         }  
  70.  
  71.         private int GetRefOutParameterCount(MethodBase method)  
  72.         {  
  73.             int count = 0;  
  74.             foreach (ParameterInfo parameter in method.GetParameters())  
  75.             {  
  76.                 if (parameter.IsOut || parameter.ParameterType.IsByRef)  
  77.                 {  
  78.                     count++;  
  79.                 }  
  80.             }  
  81.             return count;  
  82.         }  
  83.  
  84.         private void MapRefOutParameter(MethodBase method, object[] allArgs, object[] refOutArgs)  
  85.         {  
  86.             List< int> refOutParamPositionsList = new List< int>();  
  87.             foreach (ParameterInfo parameter in method.GetParameters())  
  88.             {  
  89.                 if (parameter.IsOut || parameter.ParameterType.IsByRef)  
  90.                 {  
  91.                     refOutParamPositionsList.Add(parameter.Position);  
  92.                 }  
  93.             }  
  94.             int[] refOutParamPositionArray = refOutParamPositionsList.ToArray();  
  95.             for (int i = 0; i <  refOutArgs.Length; i++)  
  96.             {  
  97.                 allArgs[refOutParamPositionArray[i]] = refOutArgs[i];  
  98.             }  
  99.         }  
  100.     }  
  101. }  

在真正的WCF客戶端框架下,客戶端通過(guò)ChannelFactory< T>創(chuàng)建服務(wù)代理對(duì)象進(jìn)行服務(wù)的調(diào)用,在這里我們也創(chuàng)建一個(gè)完成相似功能的工廠類型: SerivceProxyFactory< T>,泛型類型T代表服務(wù)契約類型。

用于創(chuàng)建服務(wù)代理的Create方法很簡(jiǎn)單:先通過(guò)Utility.Create< T>方法創(chuàng)建客戶端進(jìn)行服務(wù)調(diào)用必須的相關(guān)組件對(duì)象,通過(guò)這些對(duì)象連同該方法的參數(shù)(消息版本和服務(wù)目的地址)創(chuàng)建ServiceRealProxy< T>對(duì)象,最終返回的是該RealProxy的TransparentProxy。

  1. namespace Artech.WcfFrameworkSimulator.Client  
  2. {  
  3.     public static class SerivceProxyFactory< T>  
  4.     {  
  5.         public static T Create(MessageVersion messageVersion, Uri remoteAddress)  
  6.         {  
  7.             MessageEncoderFactory encoderFactory;  
  8.             IDictionary< string, IClientMessageFormatter> clientFormatters;  
  9.             IDictionary< string, IDispatchMessageFormatter> dispatchFormatters;  
  10.             IDictionary< string, IOperationInvoker> operationInvokers;  
  11.             IDictionary< string, MethodInfo> methods;  
  12.             Utility.Create< T>(out encoderFactory, out clientFormatters, out dispatchFormatters, out operationInvokers, out methods);  
  13.             ServiceRealProxy< T> realProxy = new ServiceRealProxy< T>(messageVersion, remoteAddress, clientFormatters, encoderFactory);  
  14.             return (T)realProxy.GetTransparentProxy();  
  15.         }  
  16.     }  

那么在最終的客戶端代碼中就可以借助SerivceProxyFactory< T>創(chuàng)建服務(wù)代理進(jìn)行服務(wù)調(diào)用了,而這里服務(wù)的目標(biāo)地址實(shí)際上是上面用于模擬WCF服務(wù)端框架的.aspx Web Page的地址。

  1. namespace Artech.WcfFrameworkSimulator.Client  
  2. {  
  3.     class Program  
  4.     {  
  5.         static void Main(string[] args)  
  6.         {  
  7.             ICalculator calculator = SerivceProxyFactory< ICalculator>.Create(MessageVersion.Default, new Uri("http://localhost/Artech.WcfFrameworkSimulator/Calculator.aspx"));  
  8.             double result = calculator.Add(12);  
  9.             Console.WriteLine("x + y = {2} when x = {0} and y = {1}"12, result);  
  10.         }  
  11.     }  

執(zhí)行結(jié)果:

x + y = 3 when x = 1 and y = 2

【編輯推薦】

  1. WCF初試,用JQuery實(shí)現(xiàn)loading的功能
  2. jQuery調(diào)用WCF服務(wù)傳遞JSON對(duì)象
  3. WCF的傳輸安全機(jī)制
  4. 詳解WCF中的變更處理:不可不知的最佳實(shí)踐
  5. 使用ASP.NET AJAX調(diào)用WCF服務(wù)項(xiàng)模板
責(zé)任編輯:yangsai 來(lái)源: 博客園
相關(guān)推薦

2009-07-27 17:46:42

WCF服務(wù)ASP.NET應(yīng)用程序

2009-07-27 17:54:39

WCF服務(wù)ASP.NET

2009-07-29 17:21:10

2009-08-04 16:24:19

合格的ASP.NET程

2009-07-27 17:38:30

WCF服務(wù)ASP.NET 3.5

2009-07-20 17:39:36

WCF服務(wù)ASP.NET AJA

2011-12-20 10:02:01

ASP.NET

2009-07-21 09:53:55

ASP.NET AJAWCF服務(wù)

2010-01-26 13:15:42

ASP.NET MVC

2009-07-27 17:51:58

WCF服務(wù)ASP.NET

2009-07-23 16:21:07

static變量ASP.NET

2009-07-23 16:44:50

XML Web服務(wù)使用ASP.NET構(gòu)造

2009-12-08 16:59:52

WCF服務(wù)

2012-08-27 10:11:43

ASP.NET

2009-04-07 16:21:35

ASP.NETAJAXWCF

2009-08-05 14:27:55

ASP.NET模板基本

2009-07-22 17:45:35

ASP.NET教程

2009-08-03 14:22:33

什么是ASP.NET

2009-07-28 17:17:19

ASP.NET概述

2009-07-22 17:32:40

ASP.NET應(yīng)用程序
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)