5、多线程与异步操作。

1)、异步服务调用:

   支持异步调用的代理类,通过注册事件的方式实现对服务的异步调用。

  异步服务代理的创建:

  对于任何一个服务操作,不管是采用异步的实现方式,还是单向的消息交换模式,我们均可以通过添加服务引用的方式创建异步服务代理,并对服务进行异步调用,方法就是在添加服务引用的对话框上,点击“高级”选项,在弹出的“服务引用设置”的对话框上,勾选“生成异步操作”即可。

  通过添加服务引用生成的服务代理类,都是继承自ClientBase<TChannel>类,勾选“生成异步操作”这个选项以后,生成的代理类里,多出了一些异步服务调用的相关的成员,比如说Add方法在服务端,生成的代理类里会出现如BeginAdd,EndAdd和AddAsync这几个异步方法,举个例子,下面是一个异步代理类生成的方法:

  [ServiceContractAttribute(Namespace=http://www.hanshuai.com)]

  public interface ICalculator

  {

    //同步操作

    [OperationContractAttribute(Action="http://www.hanshuai.com/ICalculator/Add",ReplyAction="http://www.hanshuai.com/ICalculator/AddResponse")]

    double Add(double x,double y);

 

    //异步操作

    [OperationContractAttribute(AsyncPattern=true,Action="http://www.hanshuai.com/ICalculator/Add",ReplyAction="http://www.hanshuai.com/ICalculator/AddResponse")]

    IAsyncResult BeginAdd(double x,double y,AsyncCallback callback,object asyncState);

    double EndAdd(system.IAsyncResult result);

  }

  异步调用的有3种不同的编程方式,一种是先后调用BeginAdd/EndAdd方法得到执行结果,一种是调用BeginAdd方法通过指定回调的方式得到执行结果,最后一种是调用AddAsync方法通过注册AddComplete事件的方式得到执行结果,下面逐一介绍:

  a、通过BeginXXX/EndXXX进行异步调用服务:

  通过调用BeginXXX方法会得到一个IAsyncResult对象,把这个对象传入到EndXXX方法中,最终通过EndXXX方法得到计算结果。

  CalculatorClient proxy=new CalculatorClient();

  IAsyncResult asynResult=proxy.BeginAdd(1,2,null,null);

  double result=prox.EndAdd(asynResult);//得到计算结果。

  这种方式,BeiginXXX执行完成以后,会立即执行EndXXX方法,这样没有起到异步的效果,具体可以通过回调的方式来实现异步。

  b、通过回到的方式进行异步服务调用:

  生成的异步函数BeginXXX除了具有两个操作数以外,还有另外两个参数,一个是IAsyncResult的callback,另一个是object类型的asyncState参数,其中IAsyncResult是一个无返回值的委托,参数asyncState可以向回调操作传递一些额外的参数。

  CalculatorClient proxy=new CalculatorClient();

  proxy.Begin(1,2,

        delegate(IAsyncResult asyncResult)

        {

          double[] operands=asyncResult.AsyncState as double[];

          double result=proxy.EndAdd(asyncResult);

          proxy.Close();

          Console.WriteLine("x+y={2} when x={0} and y ={1}",operands[0],operands[1],result);

        },new double[]{1,2});

  c、通过注册事件的方式实现异步服务调用:

  CalculatorClient proxy =new CalculatorClient();

  proxy.AddComplete+=delegate(object sender,AddCompleteEventArgs args)

  {

    double[] operands =args.UserState as double[];//

    double result=args.Result;

    proxy.Close();

    Console.WriteLine("x+y={2} when x={0} and y ={1}",operands[0],operands[1],result);

  };

  proxy.AddAsync(1,2,new double[]{1,2});

6、操作的选择与执行。

1)、DispatchOperation与ClientOperation:

  当ServiceHost开启的时候,以信道分发器和终结点分发器为核心的服务端的运行时框架体系被建立起来,每个终结点分发器对应着一个终结点,每个信道分发器具有自己的信道监听器,每个信道监听器具有自己一个唯一的监听地址,多个不同的终结点可以共享相同的监听地址,就是说,一个信道监听器具有一到多个终结点分发器。

  WCF会根据终结点契约得到OperationDescription列表,并创建出对应的DispatchOperation列表。

  public sealed class DispatchOperation

  {

    public string Name {get;}

    public string Action {get;}

    public string RelayAction{get;}

    public bool IsOneWay{get;}

    public bool IsTermination{get;set;}

  }

  终结点分发器初始化的时候,会建立属于它的运行时,称之为“分发运行时”:

  public sealed class DisptchRunTime

  {

    public SynchronizedKeyedCollection<string,DispatchOperation> Operations{get;}

  }

  这是运行时有个键值对的字典类型,通过键去寻找对应的分发操作。

  对于客户端来说,同样在某个终结点创建的ChannelFactory<TChannel>被开启的时候,会建立以客户端运行时框架。

  public sealed class ClientRuntime

  {

    public SynchronizedKeyedCollection<string,ClientOperation> Operations{get;}

  }

  根据对应的键值对,找到相应的ClientOperation。

2)、操作的选择:

  分发运行时,有自己的分发选择属性,即public IDispatchOperationSelector OperationSelector {get;set;},这个称为操作选择器,如果默认的分发机制不能满足我们的要求,可以通过实现IDispatchOpreationSelector接口创建自定义的操作选择器,并最终通过相应的行为应用到分发运行时上。

  对于客户端来说,ClientRuntime同样具有一样的操作选择器,public IClientOperationSelector operationSelector{get;set;}

3)、操作的执行:

  服务端,WCF定义了称为操作调用器的组件,这个组件实现了System.ServiceModel.Dispatcher.IOperationInvoke接口,这个接口提供了同步和异步的方法,同步的是Invoke方法,异步的是BeginInvoke/EndInvoke,在默认的情况下,针对同步/异步操作的执行分别是通过SyncMethodInvoker和AsyncMethodInvoke这两个操作调用器完成的,SyncMethodInvoke和AsyncMethodInvoker分别是对OperationDescription的SyncMethod和BeginMethod/EndMethod属性表示的MethodInfo对象的封装,借助于这些MethodInfo,最终通过反射的方式实现了对操作方法的调用。

 

  

 

posted on 2013-07-11 21:55  Kelly_HanShuai  阅读(136)  评论(0编辑  收藏  举报