首页 > 代码库 > WCF之消息模式

WCF之消息模式

  • 请求/响应:所有操作的默认行为,在WSDL中表现为Input/Output元素.
  • One_Way.
    • 在WSDL中只有Input,没有回应(Output),所以没有异常报告。
    • 单向操作只会在发出调用的瞬间阻塞客户端,但是如果发出了多个单向调用,WCF会把这些调用放入队列,由于队列是有限容量的,过多数量的调用会被阻塞,直到有的请求出列,然后调用入列,才会解除客户端的阻塞。
    • 当要保证消息确实到达时,使用可靠性消息/MSMQ来暂时/长期保证。
    • 其无法维持客户端状态,所以应该是终止会话前的最后一个操作.
    • 如果服务器段信道发生问题,客户端只有在下次请求时才能发现。
    • 用途.
      • 不需要报告成功与否的操作(日志,事件发布);
      • 客户端通过另一个操作来获得前一次操作结果,即轮询.
      • 用于密集型操作,每次请求得到一定的结果;
      • 双向通信,用于非密集型,只有一个最终结果,服务端完成后主动通知客户端,解放客户端。(方法的表现形式为返回类型为void,参数不能有ref,out).
  • 双向.
    • 操作可以是请求/响应或者One_way
    • WSDL中只有回调契约上有Output
    • CallBack的实现代码在客户端,由服务器端调用CallBack,且该调用的方法必须为One_way或者可重入的.
    • 客户端端点:Duplex协议,提供好了BackChannel;WSDualHttp要设置ClientBaseAdd带外调用:在服务器端,请求要被排队,然后按照先来先服务被处理,而带外处理,就是另建一个优先级较高的队列,让后来的请求有可能被先掉用.
  • 回调
    • BasicHttpBindingWSHttpBinding绑定并不支持回调.
    • 如果使用了回调,客户端生成的代理类必须继承自DuplexClientBase<T>代理类.
    • 服务对回调的调用可能死锁,解决办法: 1)将服务配置为可以多线程访问,但会增加开发的负担;2)在客户端的回调实现类的ConcurrencyMode =
      ConcurrencyMode.Reentrant
      .3)将回调设置为单向.
    • 在使用回调对象时,需要考虑到客户端代理可能关闭,此时的调用,得到一个ObjectDisposedException. 因此,对于客户端而言,当它不再需要接收回调或者客户端应用程序已经关闭时,最好能够通知服务.所以, 为服务契约增加两个操作Connect()与Disconnect().
    • 由于使用WSDualHttpBinding绑定执行回调时,需要开通两个HTTP通道,一个用于服务,一个用于回调。通常,WCF为回调通道选择了默认的80端口,但如果客户端运行了IIS,则可能会占用80端口,就会导致端口的冲突。实际上,我们可以为回调通道指定任何可用的端口,例如,我们可以通过配置文件为客户端指定基地址。然而,我们指定的端口仍然可能会被占用,只是这种占用的可能性比80端口小。为了避免潜在的端口冲突,同时简化程序员的工作,最好的办法是自动分配一个可用的端口.
  • 上下文重入(ConcurrencyMode)
    • 当对独占域拥有访问权限的线程A访问域外的方法(回调对象),有一个线程B要访问该独占域(服务对象),A会释放该域的锁以让B进入,直到B完成并释放锁后,A将重新进入该域.
    • 在客户端请求时,把自己的上下文在请求的同时发送给服务器端。服务器端处理完后,把这个上下文又发回给客户端。此上下文为C/S间共有.
    • 不可重入:客户端和服务器端互相等待上下文环境的释放。死锁(single.
    • 单线程可重入:对临界区资源很好的保护。(Reentrant).
    • 完全可重入:允许多线程对当前上下文进行处理。(Multiple).需要对临界资源进行处理。在GUI中,回调函数运行的线程必须为调用请求的线程.
  • 大消息.
    • 为了防止DOS,有一个消息的最大配额。
    • 1)MTOM:降低二进制传输的开销。方法:删除过多的无用信息,Base64编码:把2进制的8B一组改为6B一组,使数据量增大8/6倍。SOAP消息以MIME的文档多部分相关类型发送。使用时仅仅需要对配置文件进行修改。
    • 2)流传输:MTOM中整个消息被加载到内存里,开销比较大,使用流降低它,但是会损失某些特性(可靠性消息与安全性)。在客户端读取返回和服务端读取进入时要手动关闭流。而对于客户端发送和服务器返回时WCF默认自动关闭.
  • 分步操作
    • 当服务契约需要指定执行顺序时.
    • 使用操作契约的IsInitiating(默认=true)IsTerminating(=false)属性实现.
    • IsInitiating=true的操作不一定是启动会话的第一个操作,相同设置的其它方法在被调用后,会启动一个会话,而该调用被加入该会话中.但是调用IsTerminating=true的操作必为关闭会话的操作,之后,不能调用服务的任何方法,除非再创建一个代理对象. IsTerminating=true的操作也可以为IsInitiating=true,启调用开始时开启会话,但是结束时会结束会话.