WCF技术剖析之十一:异步操作在WCF中的应用(下篇)

原文:WCF技术剖析之十一:异步操作在WCF中的应用(下篇)

说完了客户端的异步服务调用(参阅WCF技术剖析之十一:异步操作在WCF中的应用(上篇)),我们在来谈谈服务端如何通过异步的方式为服务提供实现。在定义服务契约的时候,相信大家已经注意到了OperationContractAttribute特性具有一个bool类型的AsynPattern。该属性可以将一个服务操作定义成异步实现模式,接下来的内容主要是着眼于介绍异步操作的定义和实现原理。

一、异步操作的定义和实现原理

实现WCF异步服务操作模式在编程上具有一些限制:异步服务操作是通过两个配对的方法实现的,并且采用典型的异步操作命名方式:BeginXxx/EndXxx。两个方法需要采用如下的签名,指定了AsyncPattern属性的OperationContractAttribute只需要应用到BeginXxx方法上面。

   1: [OperationContract(AsyncPattern = true)]
   2: IAsyncResult BeginDoWork(parameters, AsyncCallback userCallback, object stateObject);

   3: ReturnType   EndDoWork(IAsyncResult asynResult);

比如下面两段代码可以看作相同的操作在同步和异步下的不同表现。

   1: [OperationContract]
   2: double Add(double x, double y);

   1: [OperationContract(AsyncPattern = true)]

   2: IAsyncResult BeginAdd(double x, double y, AsyncCallback userCallback, object stateObject);

   3: double EndAdd(IAsyncResult asynResult);

理解了异步操作的定义模式之后,我们来谈谈WCF异步操作实现的原理。WCF通过类型OperationDescription表示对服务操作的描述。如下面的代码所示,OperationDescription具有3个重要的MemthodInfo类型的属性成员:SyncMethod、BeginMethod和EndMethod,分别表示同步方法、异步开始和结束方法。以上面的代码为例,如果采用SyncMethod表示Add方法,而BeginMethod和EndMethod对应于BeginAdd和EndAdd方法。

   1: public class OperationDescription
   2: {  

   3:     

   4:     public MethodInfo SyncMethod { get; set; }

   5:     public MethodInfo BeginMethod { get; set; }

   6:     public MethodInfo EndMethod { get; set; }

   7:     //其他成员  

   8: }

WCF通过OperationSelector选择相应的操作,通过OperationInvoker执行被选择操作对应的方法。所有的OperationInvoker都实现了接口System.ServiceModel.Dispatcher.IOperationInvoker。下面是IOperationInvoker基本的定义。Invoke和InvokeBegin/InvokeEnd代表对操作同步和异步执行,IsSynchronous表示当前操作是否是异步的,如果操作的AsyncPattern为true则表明是异步操作。

   1: public interface IOperationInvoker
   2: {    

   3:     object[] AllocateInputs();

   4:     object Invoke(object instance, object[] inputs, out object[] outputs);

   5:     IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state);

   6:     object InvokeEnd(object instance, out object[] outputs, IAsyncResult result);   

   7:     bool IsSynchronous { get; }

   8: }

在WCF中定义了两个典型的OperationInvoker:SyncOperationInvoker与AsyncOperationInvoker,它们分别用于同步操作和异步操作的执行。这两个OperationINvoker均实现了IOperationInvoker接口,SyncOperationInvoker实现了Invoke方法,AsyncOperationInvoker实现了InvokeBegin和InvokeEnd

当通过OperationSelector和InstanceProvider选出正确的方法和得到相应的服务实例的时候,WCF根据操作的AsyncPattern选择相应的OperationInvoker。如果是同步的则自然选择SyncOperationInvoker,执行Invoke方法。Invoke方法会通过OperationDescription的SyncMethod属性,得到同步操作方法的MethodInfo,采用反射的机制执行该方法;对于异步操作,则会调用AsyncOperationInvoker的InvokeBegin和InvokeEnd方法,InvokeBegin和InvokeEnd方法对应的MethodInfo通过OperationDescription的BeginMethod和EndMethod属性获得。得到相应的MethodInfo对象后,同样通过反射调用服务实例。

二、如何创建异步服务

在了解了异步操作的定义和具体的实现原理之后,我们通过一个简单的实例演示异步操作在WCF应用中的实现。本例子中,我们通过服务调用来读取服务端的文件,在实现文件读取操作的时候,采用异步文件读取方式。

先来看看服务契约的定义。服务契约通过接口IFileReader定义,基于文件名的文件读取操作以异步的方式定义在BeginRead和EndRead方法中。

   1: using System;
   2: using System.ServiceModel;

   3: namespace Artech.AsyncServices.Contracts

   4: {

   5:     [ServiceContract(Namespace="http://www.artech.com/")]

   6:     public interface IFileReader

   7:     {

   8:         [OperationContract(AsyncPattern = true)]

   9:         IAsyncResult BeginRead(string fileName, AsyncCallback userCallback, object stateObject);

  10:  

  11:         string EndRead(IAsyncResult asynResult);

  12:     }

  13: }

FileReader实现了契约契约,在BeginRead方法中,根据文件名称创建FileStream对象,调用FileStream的BeginRead方法实现文件的异步读取,并直接返回该方法的执行结果:一个IAsyncResult对象。在EndRead方法中,调用FileStream的EndRead读取文件内容,并关闭FileStream对象。

   1: using System;
   2: using System.Text;

   3: using Artech.AsyncServices.Contracts;

   4: using System.IO;

   5: namespace Artech.AsyncServices.Services

   6: {

   7:     public class FileReaderService : IFileReader

   8:     {

   9:         private const string baseLocation = @"E:\";

  10:         private FileStream _stream;

  11:         private byte[] _buffer;

  12:  

  13:         #region IFileReader Members

  14:  

  15:         public IAsyncResult BeginRead(string fileName, AsyncCallback userCallback, object stateObject)

  16:         {

  17:             this._stream = new FileStream(baseLocation + fileName, FileMode.Open, FileAccess.Read, FileShare.Read);

  18:             this._buffer = new byte[this._stream.Length];

  19:             return this._stream.BeginRead(this._buffer, 0, this._buffer.Length, userCallback, stateObject);

  20:         }

  21:  

  22:         public string EndRead(IAsyncResult ar)

  23:         {

  24:             this._stream.EndRead(ar);

  25:             this._stream.Close();

  26:             return Encoding.ASCII.GetString(this._buffer);

  27:         }

  28:  

  29:         #endregion

  30:     }

  31: }

采用传统的方式寄宿该服务,并发布元数据。在客户端通过添加服务引用的方式生成相关的服务代理代码和配置。你将会发现客户端生成的服务契约和服务代理类中,会有一个唯一的操作Read。也就是说,不管服务采用同步模式还是异步模式实现,对客户端的服务调用方式没有任何影响,客户端可以任意选择相应的模式进行服务调用。

   1: namespace Clients.ServiceReferences
   2: {

   3:     [ServiceContractAttribute(ConfigurationName= "ServiceReferences.IFileReader")]

   4:     public interface IFileReader

   5:     {

   6:         [OperationContractAttribute(Action = " http://www.artech.com/IFileReader/Read", ReplyAction = " http://www.artech.com/IFileReader/ReadResponse")]

   7:         string Read(string fileName);

   8:     }

   9:  

  10:     public partial class FileReaderClient : ClientBase<IFileReader>, IFileReader

  11:     {

  12:  

  13:         public string Read(string fileName)

  14:         {

  15:             return base.Channel.Read(fileName);

  16:         }

  17:     }

  18: }

直接借助于生成的服务代理类FileReaderClient,服务调用的代码就显得很简单了。

   1: using System;
   2: using Clients.ServiceReferences;

   3: namespace Clients

   4: {

   5:     class Program

   6:     {

   7:         static void Main(string[] args)

   8:         {

   9:             using (FileReaderClient proxy = new FileReaderClient())

  10:             { 

  11:                 Console.WriteLine(proxy.Read("test.txt"));

  12:             }

  13:             Console.Read();

  14:         }

  15:     }

  16: }

时间: 2024-10-10 11:53:14

WCF技术剖析之十一:异步操作在WCF中的应用(下篇)的相关文章

WCF技术剖析之十一:异步操作在WCF中的应用(上篇)

原文:WCF技术剖析之十一:异步操作在WCF中的应用(上篇) 按照操作执行所需的资源类型,我们可以将操作分为CPU绑定型(CPU Bound)操作和I/O绑定型(I/O Bound)操作.对于前者,操作的执行主要利用CPU进行密集的计算,而对于后者,大部分的操作处理时间花在I/O操作处理,比如访问数据库.文件系统.网络资源等.对于I/O绑定型操作,我们可以充分利用多线程的机制,让多个操作在自己的线程并发执行,从而提高系统性能和响应能力.服务调用就是典型的I/O绑定型操作,所以多线程在服务调用中具

WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理

原文:WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理 在前面一片文章(服务代理不能得到及时关闭会有什么后果?)中,我们谈到及时关闭服务代理(Service Proxy)在一个高并发环境下的重要意义,并阐明了其根本原因.但是,是否直接调用ICommunicationObject的Close方法将服务代理关闭就万事大吉了呢?事情远不会这么简单,这其中还会涉及关于异常处理的一些操作,这就是本篇文章需要讨论的话题. 一.异常的抛出与Close的失败 一般情况下,当服务端抛出异常,客户客户

WCF技术剖析之七:如何实现WCF与EnterLib PIAB、Unity之间的集成

原文:WCF技术剖析之七:如何实现WCF与EnterLib PIAB.Unity之间的集成 在这之前,我写过深入介绍MS EnterLib PIAB的文章(参阅<MS Enterprise Library Policy Injection Application Block 深入解析[总结篇]>),也写过WCF与PIAB的集成(参阅:<WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Applicat

《WCF技术剖析》博文系列汇总[持续更新中]

http://www.cnblogs.com/artech/archive/2009/11/21/1607686.html 近半年以来,一直忙于我的第一本WCF专著<WCF技术剖析(卷1)>的写作,一直无暇管理自己的Blog.在<WCF技术剖析(卷1)>写作期间,对WCF又有了新的感悟,为此以书名开始本人的第三个WCF系列.本系列的目的在于对<WCF技术剖析>的补充,会对书中的一些内容进行展开讲述,同时会囊括很多由于篇幅的原因忍痛割弃的内容. [第1篇] 通过一个ASP

WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化

在本篇文章中,我们将讨论WCF四大契约(服务契约.数据契约.消息契约和错误契约)之一的消息契约(Message Contract).服务契约关注于对服务操作的描述,数据契约关注于对于数据结构和格式的描述,而消息契约关注的是类型成员与消息元素的匹配关系. 我们知道只有可序列化的对象才能通过服务调用在客户端和服务端之间进行传递.到目前为止,我们知道的可序列化类型有两种:一种是应用了System.SerializableAttribute特性或者实现了System.Runtime.Serializat

WCF技术剖析之三十:一个很有用的WCF调用编程技巧[下篇]

原文:WCF技术剖析之三十:一个很有用的WCF调用编程技巧[下篇] 在<上篇>中,我通过使用Delegate的方式解决了服务调用过程中的异常处理以及对服务代理的关闭.对于<WCF技术剖析(卷1)>的读者,应该会知道在第7章中我通过类似于AOP的方式解决了相似的问题,现在我们来讨论这个解决方案. 通过<服务代理不能得到及时关闭会有什么后果?>的介绍,我们知道了及时关闭服务代理的重要意义,并且给出了正确的编程方式.如果严格按照上面的编程方式,就意味着对于每一个服务调用,都要

WCF技术剖析之三十:一个很有用的WCF调用编程技巧[上篇]

原文:WCF技术剖析之三十:一个很有用的WCF调用编程技巧[上篇] 在进行基于会话信道的WCF服务调用中,由于受到并发信道数量的限制,我们需要及时的关闭信道:当遇到某些异常,我们需要强行中止(Abort)信道,相关的原理,可以参考我的文章<服务代理不能得到及时关闭会有什么后果?>.在真正的企业级开发中,正如我们一般不会让开发人员手工控制数据库连接的开启和关闭一样,我们一般也不会让开发人员手工去创建.开启.中止和关闭信道,这些工作是框架应该完成的操作.这篇文章,我们就来介绍如果通过一些编程技巧,

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

原文:WCF技术剖析之一:通过一个ASP.NET程序模拟WCF基础架构 细算起来,已经有好几个月没有真正的写过文章了.近半年以来,一直忙于我的第一本WCF专著<WCF技术剖析>的写作,一直无暇管理自己的Blog.到目前为止<WCF技术剖析(卷1)>的写作暂告一段落,初步预计于下个月由武汉博文视点出版.在<WCF技术剖析>写作期间,对WCF又有了新的感悟,为此以书名开始本人的第三个WCF系列.本系列的目的在于对<WCF技术剖析>的补充,会对书中的一些内容进行展

WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载]

原文:WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载] 我们有两种典型的WCF调用方式:通过SvcUtil.exe(或者添加Web引用)导入发布的服务元数据生成服务代理相关的代码和配置:通过ChannelFactory<TChannel>创建服务代理对象.在这篇文章中,我们采用一种独特的方式进行服务的调用.从本质上讲,我们只要能够创建于服务端相匹配的终结点,就能够实现正常的服务调用.在WCF客户端元数据架构体系中,利用MetadataExchangeClient可以获取服