WCF的基本编程 设计服务协定 如何:创建单工协定

如何:创建单向协定

本主题演示了创建使用单向协定的方法所需的基本步骤。这些方法从客户端调用 Windows Communication Foundation (WCF) 服务上的操作但不期待答复。例如,可以使用这种类型的协定将通知发布给许多订户。在创建双工(双向)协定(可使得客户端和服务器可以独立地相互通信,这样双方都可以启动对另一方的呼叫)时,还可以使用单向协定。具体而言,这样做可允许服务器对客户端进行单向呼叫,而客户端可以将这些呼叫视为事件。有关指定单向方法的详细信息,请参见 IsOneWay 属性和 OperationContractAttribute 类。

有关 创建用于双工协定的客户端应用程序的更多信息,请参见如何:使用单向和请求-答复协定访问 WCF 服务。有关可运行的示例,请参见Service Contract: One-Way示例。

创建单向协定

  1. 通过将 ServiceContractAttribute 类应用到定义服务将要实现的方法的接口,创建服务协定。

  2. 通过将 OperationContractAttribute 类应用到相应的方法,指示客户端可以调用接口中的哪些方法。

  3. 通过将 IsOneWay 属性设置为 true,可将不得具有输出(没有返回值且没有 out 参数或 ref 参数)的操作指定为单向操作。注意,默认情况下,使用 OperationContractAttribute 类的操作都满足请求-答复协定,原因是默认情况下 IsOneWay 属性为 false。因此,如果需要对方法使用单向协定,则必须将 attribute 属性的值显式指定为 true

 

此示例演示具有单向服务操作的服务协定。客户端不会像在双向服务操作中那样等待服务操作完成。此示例基于入门示例并使用 wsHttpBinding 绑定。此示例中的服务是自承载控制台应用程序,通过它可以观察接收和处理请求的服务。客户端也是一个控制台应用程序。

注意:
本主题的末尾介绍了此示例的设置过程和生成说明。

 

 

若要创建单向服务协定,请定义服务协定,将 OperationContractAttribute 类应用于每个操作,并将 IsOneWay 设置为 true,如下面的示例代码所示:

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
            public interface IOneWayCalculator
            {
            [OperationContract(IsOneWay=true)]
            void Add(double n1, double n2);
            [OperationContract(IsOneWay = true)]
            void Subtract(double n1, double n2);
            [OperationContract(IsOneWay = true)]
            void Multiply(double n1, double n2);
            [OperationContract(IsOneWay = true)]
            void Divide(double n1, double n2);
            }
            

为了演示客户端不会等待服务操作完成,此示例中的服务代码实现了五秒钟的延迟,如下面的示例代码所示:

/ This service class implements the service contract.
            // This code writes output to the console window.
            [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,    InstanceContextMode = InstanceContextMode.PerCall)]
            public class CalculatorService : IOneWayCalculator
            {
            public void Add(double n1, double n2)
            {
            Console.WriteLine("Received Add({0},{1}) - sleeping", n1, n2);
            System.Threading.Thread.Sleep(1000 * 5);
            double result = n1 + n2;
            Console.WriteLine("Processing Add({0},{1}) - result: {2}", n1, n2, result);
            }
            ...
            }
            

当客户端调用服务时,调用不等待服务操作完成即返回。

运行示例时,客户端和服务活动将显示在服务和客户端控制台窗口中。您可以看到服务从客户端接收消息。在每个控制台窗口中按 Enter 可以同时关闭服务和客户端。

客户端在服务之前完成,说明了客户端没有等待单向服务操作完成。客户端输出如下所示:

Add(100,15.99)
            Subtract(145,76.54)
            Multiply(9,81.25)
            Divide(22,7)
            Press <ENTER> to terminate client.
            

服务输出如下所示:

The service is ready.
            Press <ENTER> to terminate service.
            Received Add(100,15.99) - sleeping
            Received Subtract(145,76.54) - sleeping
            Received Multiply(9,81.25) - sleeping
            Received Divide(22,7) - sleeping
            Processing Add(100,15.99) - result: 115.99
            Processing Subtract(145,76.54) - result: 68.46
            Processing Multiply(9,81.25) - result: 731.25
            Processing Divide(22,7) - result: 3.14285714285714
            
注意:
HTTP 从定义上讲是一个请求/响应协议;当发出请求时,即返回响应。即使对于通过 HTTP 公开的单向服务操作,也是如此。当调用操作时,服务在执行服务操作之前返回 HTTP 状态码 202。此状态码表示请求已被接受进行处理,但处理尚未完成。调用操作的客户端在从服务收到 202 响应之前处于阻止状态。当使用绑定(配置为使用会话)发送多个单向消息时,这可能会产生某些意外行为。此示例中使用的 wsHttpBinding 绑定配置为默认使用会话来建立安全上下文。默认情况下,会话中的消息一定会按照它们的发送顺序到达。因此,当发送会话中的第二个消息时,在处理完第一个消息之前不会处理第二个消息。这样的结果是,在处理完上一个消息之前,客户端不会收到消息的 202 响应。因此,客户端似乎是阻止了每个后续的操作调用。为了避免此行为,此示例对运行库进行了配置,以便将消息并发调度给不同的实例进行处理。此示例将 InstanceContextMode 设置为 PerCall,使每个消息可以由不同的实例来处理。ConcurrencyMode 设置为 Multiple,以允许多个线程同时调度消息。
posted @ 2008-11-10 21:57  木饭  阅读(292)  评论(0编辑  收藏  举报