`
varsoft
  • 浏览: 2435186 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

[原创]WCF技术剖析之一:通过一个ASP.NET程序模拟WCF基础架构

阅读更多

细算起来,已经有好几个月没有真正的写过文章了。近半年以来,一直忙于我的第一本WCF专著《WCF技术剖析》的写作,一直无暇管理自己的Blog。到目前为止《WCF技术剖析(卷1)》的写作暂告一段落,初步预计于下个月由武汉博文视点出版。在《WCF技术剖析》写作期间,对WCF又有了新的感悟,为此以书名开始本人的第三个WCF系列。本系列的目的在于对《WCF技术剖析》的补充,会对书中的一些内容进行展开讲述,同时会囊括很多由于篇幅的原因忍痛割弃的内容。

本系列的第一篇,我将会对WCF的基本架构作一个大致的讲解。不过,一改传统对WCF的工作流程进行平铺直叙,我将另辟蹊径,借助于我们熟悉的ASP.NET作为请求处理平台,通过一个简单的托管程序模拟整个WCF客户端和服务端的架构。Source Code下载:Artech.WcfFrameworkSimulator.zip

WCF框架处理流程和涉及的组件

我们的模拟程序将你搭建一个迷你版的WCF框架,为了展示WCF整个处理流程中使用到一些特殊组件。我们首先来简单介绍一下对于一个简单的WCF服务调用,WCF的客户端和服务端框架的处理流程,和该流程的每一个阶段都使用那些重要组件。

下面的列表列出了WCF服务端框架对于处理一个简单的WCF服务调用请求所提供的功能,以及相应的功能承载的组件:

  • 请求消息的接收和回复消息的发送:服务端在传输层监听与接收来自客户的请求,并将经过编码后的回复消息通过传输层发送到客户端
  • 请求消息的解码和回复消息的编码:将接收到的字节数组通过解码生成请求消息对象,并将回复消息通过编程转化成字节组。消息的编码和解码通过MessageEncoder完成,而MessageEncoderFactory负责创建该对象
  • 请求消息的反序列化和回复消息的序列化:对请求消息进行反序列化,为服务操作的执行生成相应的输入参数,以及将服务操作执行的结果(返回值或者ref/out参数)序列化,并生成回复消息。序列化和反序列化通过DispatchMessageFormatter完成
  • 服务对象的创建:创建或者激活服务对象实例,InstanceProvider用于服务对象的创建或获取
  • 服务操作的执行:调用创建的服务对象的操作方法,并传入经过反序列化生成的输入参数。OperationInvoker完成对服务操作的最终执行

较之服务端的流程,客户端的流程显得相对简单,仅仅包含以下三个必需的阶段:

  • 请求消息的序列化和回复消息的反序列化:生成请求消息并将输入参数序列化到请求消息中,以及对回复消息进行反序列化,转化成方法调用的返回值或者ref/out参数。序列化和反序列化通过ClienthMessageFormatter完成
  • 请求消息的编码和回复消息的解码:对请求消息进行编码生成字节数组供传输层发送,以及将传输层接收到的字节数组解码生成恢复消息。消息的编码和解码通过MessageEncoder完成,而MessageEncoderFactory负责创建该对象
  • 请求消息的发送和回复消息的接收:在传输层将经过编码的请求消息发送到服务端,以及将接收来自服务端的恢复消息

clip_image002

图1 精简版WCF客户端与服务端组件

图1反映了进行服务调用的必要步骤和使用到的相关WCF组件。在本案例演示中,我们需要做的就是手工创建这些组件,并通过我们自己的代码利用它们搭建一个简易版的WCF框架。如果读者能够对本案例的实现有一个清晰的理解,相信对于整个WCF的框架就不会感到陌生了。

图2显示了本案例解决方案的基本结构,总共分三个项目。Contracts用于定义服务契约,被服务端和客户端引用。客户端通过一个Console应用模拟,而服务端则通过一个ASP.NET Website实现。

clip_image002[5]

图2 WCF框架模拟案例应用结构

步骤一、通过服务契约类型创建相关组件

WCF在整个服务调用生命周期的不同阶段,会使用到不同的组件。我们通过一个方法将服务端和客户端所需的所有组件都创建出来,为此,我们在Contracts项目中添加了一个Utility类型,在Create<T>方法中创建所有的组件并通过输出参数的形式返回,泛型类型T表示的是服务契约类型。在该方法中,输出参数encoderFactory被服务端和客户端用于消息的编码和解码,clientFormatters和dispatchFormatters以字典的形式包含了基于服务操作的IClientMessageFormatter和IDispatchMessageFormatter,其中clientFormatters和dispatchFormatters的Key分别为操作名称和操作对应的Action。同样通过字典形式返回的operationInvokers和methods用于在服务端执行相应的操作方法,Key同样为操作对应的Action。

   1: public static class Utility
<!--CRLF-->
   2: {
<!--CRLF-->
   3:     public static void Create<T>(out MessageEncoderFactory encoderFactory,
<!--CRLF-->
   4:         out IDictionary<string, IClientMessageFormatter> clientFormatters,
<!--CRLF-->
   5:         out IDictionary<string, IDispatchMessageFormatter> dispatchFormatters,
<!--CRLF-->
   6:         out IDictionary<string, IOperationInvoker> operationInvokers,
<!--CRLF-->
   7:         out IDictionary<string, MethodInfo> methods)
<!--CRLF-->
   8:     {
<!--CRLF-->
   9:         //省略实现
<!--CRLF-->
  10:     }
<!--CRLF-->
  11: }
<!--CRLF-->
具体的实现如下,由于在WCF框架中使用的MessageEncoderFactory(TextMessageEncoderFactory)、MessageFormatter(DataContractSerializerOperationFormatter)和OperationInvoker(SyncMethodInvoker)都是一些内部类型,所以只能通过反射的方式创建它们。而操作名称和Action也主要通过反射的原理解析应用在服务方法上的OperationContractAttribute得到。
   1: public static void Create<T>(out MessageEncoderFactory encoderFactory,
<!--CRLF-->
   2:     out IDictionary<string, IClientMessageFormatter> clientFormatters,
<!--CRLF-->
   3:     out IDictionary<string, IDispatchMessageFormatter> dispatchFormatters,
<!--CRLF-->
   4:     out IDictionary<string, IOperationInvoker> operationInvokers,
<!--CRLF-->
   5:     out IDictionary<string, MethodInfo> methods)
<!--CRLF-->
   6: {
<!--CRLF-->
   7:     //确保类型T是应用了ServiceContractAttribute的服务契约
<!--CRLF-->
   8:     object[] attributes = typeof(T).GetCustomAttributes(typeof(ServiceContractAttribute), false);
<!--CRLF-->
   9:     if (attributes.Length == 0)
<!--CRLF-->
  10:     {
<!--CRLF-->
  11:         throw new InvalidOperationException(string.Format("The type \"{0}\" is not a ServiceContract!", typeof(T).AssemblyQualifiedName));
<!--CRLF-->
  12:     } 
<!--CRLF-->
  13: 
<!--CRLF-->
  14:     //创建字典保存IClientMessageFormatter、IDispatchMessageFormatter、IOperationInvoker和MethodInfo
<!--CRLF-->
  15:     clientFormatters = new Dictionary<string, IClientMessageFormatter>();
<!--CRLF-->
  16:     dispatchFormatters = new Dictionary<string, IDispatchMessageFormatter>();
<!--CRLF-->
  17:     operationInvokers = new Dictionary<string, IOperationInvoker>();
<!--CRLF-->
  18:     methods = new Dictionary<string, MethodInfo>(); 
<!--CRLF-->
  19: 
<!--CRLF-->
  20:     //MessageEncoderFactory
<!--CRLF-->
  21:     string encoderFactoryType = "System.ServiceModel.Channels.TextMessageEncoderFactory,System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
<!--CRLF-->
  22:     encoderFactory = (MessageEncoderFactory)Activator.CreateInstance(Type.GetType(encoderFactoryType), MessageVersion.Default, Encoding.UTF8, int.MaxValue, int.MaxValue, new XmlDictionaryReaderQuotas()); 
<!--CRLF-->
  23: 
<!--CRLF-->
  24: //得到OperationDecription列表
<!--CRLF-->
  25: string defaultNamespace = "http://tempuri.org/";
<!--CRLF-->
  26:     ServiceContractAttribute serviceAttribute = (ServiceContractAttribute)attributes[0];
<!--CRLF-->
  27:     string serviceNamepace = string.IsNullOrEmpty(serviceAttribute.Namespace) ? defaultNamespace : serviceAttribute.Namespace;
<!--CRLF-->
  28:     string serviceName = string.IsNullOrEmpty(serviceAttribute.Name) ? typeof(T).Name : serviceAttribute.Name;
<!--CRLF-->
  29:     var operations = ContractDescription.GetContract(typeof(T)).Operations; 
<!--CRLF-->
  30: 
<!--CRLF-->
  31:     //得到具体的IClientMessageFormatter、IDispatchMessageFormatter和IOperationInvoker的具体类型
<!--CRLF-->
  32:     //IClientMessageFormatter+IDispatchMessageFormatter:DataContractSerializerOperationFormatter
<!--CRLF-->
  33:     //IOperationInvoker:SyncMethodInvoker
<!--CRLF-->
  34:     string formatterTypeName = "System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter,System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
<!--CRLF-->
  35:     Type formatterType = Type.GetType(formatterTypeName);
<!--CRLF-->
  36:     ConstructorInfo formatterConstructor = formatterType.GetConstructor(new Type[] { typeof(OperationDescription), typeof(DataContractFormatAttribute), typeof(DataContractSerializerOperationBehavior) });
<!--CRLF-->
  37:     string operationInvokerTypeName = "System.ServiceModel.Dispatcher.SyncMethodInvoker,System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
<!--CRLF-->
  38:     Type operationInvokerType = Type.GetType(operationInvokerTypeName); 
<!--CRLF-->
  39: 
<!--CRLF-->
  40:     foreach (MethodInfo method in typeof(T).GetMethods())
<!--CRLF-->
  41:     {
<!--CRLF-->
  42:         attributes = method.GetCustomAttributes(typeof(OperationContractAttribute), true);
<!--CRLF-->
  43:         if (attributes.Length > 0)
<!--CRLF-->
  44:         {
<!--CRLF-->
  45:             OperationContractAttribute operationAttribute = (OperationContractAttribute)attributes[0];
<!--CRLF-->
  46:             string operationName = string.IsNullOrEmpty(operationAttribute.Name) ? method.Name : operationAttribute.Name;
<!--CRLF-->
  47:             //通过OperationContractAttribute得到Action
<!--CRLF-->
  48:             string action;
<!--CRLF-->
  49:             if (string.IsNullOrEmpty(operationAttribute.Action))
<!--CRLF-->
  50:             {
<!--CRLF-->
  51:                 action = string.Format("{0}{1}/{2}", serviceNamepace, serviceName, operationName);
<!--CRLF-->
  52:             }
<!--CRLF-->
  53:             else
<!--CRLF-->
  54:             {
<!--CRLF-->
  55:                 action = operationAttribute.Action;
<!--CRLF-->
  56:             } 
<!--CRLF-->
  57: 
<!--CRLF-->
  58:             OperationDescription operation = operations.Where(op => op.Name == operationName).ToArray<OperationDescription>()[0];
<!--CRLF-->
  59:             //通过反射创建DataContractSerializerOperationFormatter对象
<!--CRLF-->
  60:             object formatter = formatterConstructor.Invoke(new object[] { operation, new DataContractFormatAttribute(), null });
<!--CRLF-->
  61:             clientFormatters.Add(operationName, formatter as IClientMessageFormatter);
<!--CRLF-->
  62:             dispatchFormatters.Add(action, formatter as IDispatchMessageFormatter); 
<!--CRLF-->
  63: 
<!--CRLF-->
  64:             //通过反射创建SyncMethodInvoker对象
<!--CRLF-->
  65:             IOperationInvoker operationInvoker = (IOperationInvoker)Activator.CreateInstance(operationInvokerType, method);
<!--CRLF-->
  66:             operationInvokers.Add(action, operationInvoker);
<!--CRLF-->
  67:             methods.Add(action, method);
<!--CRLF-->
  68:         }
<!--CRLF-->
  69: }
<!--CRLF-->

步骤二、创建服务契约和实现服务

接下来为本案例创建一个服务契约和实现该契约。服务契约定义在Contracts项目,具体的服务实现在模拟服务端的ASP.NET Web站点中。简单起见,依然沿用计算服务的例子。

   1: [ServiceContract(Namespace = "http://www.artech.com/")]
<!--CRLF-->
   2:     public interface ICalculator
<!--CRLF-->
   3:     {
<!--CRLF-->
   4:         [OperationContract]
<!--CRLF-->
   5:         double Add(double x, double y);
<!--CRLF-->
   6:     }
<!--CRLF-->
   1: public class CalculatorService : ICalculator
<!--CRLF-->
   2: {
<!--CRLF-->
   3:     public double Add(double x, double y)
<!--CRLF-->
   4:     {
<!--CRLF-->
   5:         return x + y;
<!--CRLF-->
   6:     }
<!--CRLF-->
   7: }
<!--CRLF-->

步骤三、实现服务端对服务调用请求的处理

我们通过一个ASP.NET的Web Page来模拟WCF服务端对服务请求的处理,下面的Calculator类型相关的代码实际上就是Calculator.aspx的后台代码(Code Behind)。整个处理流程不算复杂。在构造函数中,调用Utility的Create<ICalculator>方法,将所需的组件进行初始化,而具体的服务调用请求处理的逻辑在直接写在Web Page的Load事件中。

首先,通过MessageCoderFactory创建MessageEncoder对接收到的以HttpRequest形式体现的服务调用请求进行解码,并生成请求消息。通过请求消息得到当前服务操作的Action属性后,在初始化过程中得到的基于服务契约所有MethodInfo列表中,根据该Action得到当前操作对应的MethodInfo对象。借助于MethodInfo对象得到操作方法的输入参数和输出参数数量后,创建两个对象数组,分别用于保存通过DispatchMessageFormatter对象对于请求消息进行反序列化得到的输入参数,和通过OperationInvoker执行操作方法得到的输出参数。在OperationInvoker执行操作方法之前,通过反射的方式直接创建服务对象,这一步在真正的WCF框架中是通过InstanceProvider实现的。

通过OperationInvoker执行操作方法的结果有两种形式:返回值和输出参数(包括引用参数)。它们通过被传入DispatchMessageFormatter被序列

分享到:
评论

相关推荐

    ASP.NET3.5从入门到精通

    为了能够方便读者的学习,本书前面几个章节详细的讲解了ASP.NET 开发工具的安装,数据库系统的 安装以及ASP.NET 的基本知识。ASP.NET 使用的是面向对象的思想进行应用程序开发,本书还详细的讲解 了面向对象的概念...

    ASP.NET 3.5 开发大全

    本书在实例章节中,详细的介绍了如何进行规范的应用程序开发,包括设计需求分析文档以及编写类图等,规范的应用程序开发是非常重要的,同时本书还介绍了ASP.NET应用程序开发技巧,以便读者能够规范的、快速的编写...

    《C#与.NET 4高级程序设计:第5版》源码

    此为《C#与.NET 4高级程序设计:第5版》中文版一书的源码。 Amazon超级畅销书,权威新版王者归来 全面涵盖C# 2010,用IL深入揭示语言特性 多位微软MVP联手翻译,名著佳译相得益彰 本书是C# 领域久负盛名的经典著作...

    C#与.NET3.5高级程序设计Code

    书中介绍了c#的各种语言构造、.net 2.0的类、核心api、公共中间语言(cil)、动态程序集和asp.net扩展等内容;同时也介绍了.net 3.0和.net 3.5中新的编程api,包括wpf 、wcf和wf 的功能;另外,还介绍了最新的c# 3.0...

    WCF技术剖析CMH格式

    蒋金楠,网名Artech,现就职于某知名软件公司,担任高级软件顾问(Senior Software Consultant)。微软解决方案架构(Solutions ...属国内较早接触WCF的人之一,同时对.NET Remoting、MSMQ通信技术有深入的理解。

    MSDN_08年第一期

    本期MSDN杂志的主要内容有: ...• 非常 ASP.NET: 使用 ASP.NET 控件封装 Silverlight • { End Bracket }: 技术人员的激情 • 编者按: 新年新视角 • 工具箱: 高级单元测试、对象模拟、剖析应用程序及更多内容

    ASP.NET 3.5 开发大全(全方位学习+实例)

    本书在实例章节中,详细的介绍了如何进行规范的应用程序开发,包括设计需求分析文档以及编写类图等,规范的应用程序开发是非常重要的,同时本书还介绍了ASP.NET应用程序开发技巧,以便读者能够规范的、快速的编写...

    ASP.NET 3.5 开发大全(全方位学习+实例)_002

    本书在实例章节中,详细的介绍了如何进行规范的应用程序开发,包括设计需求分析文档以及编写类图等,规范的应用程序开发是非常重要的,同时本书还介绍了ASP.NET应用程序开发技巧,以便读者能够规范的、快速的编写...

    ASP.NET 3.5 开发大全(全方位学习+实例)_003

    本书在实例章节中,详细的介绍了如何进行规范的应用程序开发,包括设计需求分析文档以及编写类图等,规范的应用程序开发是非常重要的,同时本书还介绍了ASP.NET应用程序开发技巧,以便读者能够规范的、快速的编写...

    ASP.NET 3.5 开发大全word课件

    1.5 ASP.NET应用程序基础 1.5.1 创建ASP.NET应用程序 1.5.2 运行ASP.NET应用程序 1.5.3 编译ASP.NET应用程序 1.6 小结 第2章 C# 3.0程序设计基础 2.1 C#程序 2.1.1 C#程序的结构 2.1.2 C# IDE的代码设置 2.2 变量 ...

    C#与.NET 3.5 高级程序设计(第四版)pdf

    书中介绍了C#的各种语言构造、.NET 2.0的类、核心API、公共中间语言(CIL)、动态程序集和ASP.NET扩展等内容;同时也介绍了.NET 3.0和.NET 3.5中新的编程API,包括WPF 、WCF和WF 的功能;另外,还介绍了最新的C# 3.0...

    ASP.NET 3.5 开发大全11-15

    1.5 ASP.NET应用程序基础 1.5.1 创建ASP.NET应用程序 1.5.2 运行ASP.NET应用程序 1.5.3 编译ASP.NET应用程序 1.6 小结 第2章 C# 3.0程序设计基础 2.1 C#程序 2.1.1 C#程序的结构 2.1.2 C# IDE的代码设置 2.2 变量 ...

    ASP.NET 3.5 开发大全1-5

    1.5 ASP.NET应用程序基础 1.5.1 创建ASP.NET应用程序 1.5.2 运行ASP.NET应用程序 1.5.3 编译ASP.NET应用程序 1.6 小结 第2章 C# 3.0程序设计基础 2.1 C#程序 2.1.1 C#程序的结构 2.1.2 C# IDE的代码设置 2.2 变量 ...

    C# 2010 与.NET 4高级程序设计(第5版)

    书中介绍了C# 的各种语言构造、.NET 2.0 的类、核心API 、公共中间语言(CIL)、动态程序集和ASP.NET 扩展等内容;同时也介绍了.NET 3.0 和.NET 4 中新的编程API,包括WPF 、WCF 和WF 的功能;另外,还介绍了最新的...

    《C#与.NET 3.5高级程序设计》(第4版) 7-3

    《C#与.NET 3.5高级程序设计》(第4版)是C#领域久负盛名的经典著作,深入全面地叙述了C#编程语言和.NET平台核心,并以大量示例剖析相关概念。书中介绍了C#的各种语言构造、.NET 2.0的类、核心API、公共中间语言(CIL)...

    ASP.NET3.5典型模块开发源代码

    11.2.4 一个高质量的缩略图水印模块 133 11.3 使用第三方组件生成缩略图水印 136 11.3.1 “AspJpeg”组件的功能特点 136 11.3.2 在项目中添加“AspJpeg”组件 137 11.3.3 使用“AspNetImage”组件生成缩略...

    C#与.NET3.5高级程序设计Part2(中文高清完整版-共四卷)

    《C#与.NET3.5高级程序设计(第4版)》是C#领域久负盛名的经典著作,深入全面地叙述了C#编程语言和.NET平台核心,并以大量示例剖析相关概念。书中介绍了C#的各种语言构造、.NET2.0的类、核心API、公共中间语言(CIL)、...

    ASP.NET 实用案例教程

    书中介绍了C# 的各种语言构造、.NET 2.0 的类、核心API、公共中间语言(CIL)、动态程序集和ASP.NET 扩展等内容;同时也介绍了.NET 3.0 中的新的编程API 包括WPF、WCF 和WF 的功能;另外,还介绍了最新的C# 3.0 编程...

Global site tag (gtag.js) - Google Analytics