首页 > 代码库 > wcf中的使用全双工通信(转)

wcf中的使用全双工通信(转)

wcf中的契约通信默认是请求恢复的方式,当客户端发出请求后,一直到服务端回复时,才可以继续执行下面的代码。

除了使用请求应答方式的通信外,还可以使用全双工。下面给出例子:

1.添加一个wcf类库

image

2.在服务契约添加如下一个片段

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode = SessionMode.Required, 
        CallbackContract = typeof(ICalculatorDuplexCallback))]

public interface ICalculatorDuplex 
   { 
       [OperationContract(IsOneWay = true)] 
       void Clear(); 
       [OperationContract(IsOneWay = true)] 
       void AddTo(double n); 
       [OperationContract(IsOneWay = true)] 
       void SubtractFrom(double n); 
       [OperationContract(IsOneWay = true)] 
       void MultiplyBy(double n); 
       [OperationContract(IsOneWay = true)] 
       void DivideBy(double n); 
   }

其中ICalculatorDuplexCallback为实现全双工客户端的接口

3.定义ICalculatorDuplexCallback接口。该接口目的主要是回调客户端的方法。和服务端无关,所以让该接口的方法设置为单向的

public interface ICalculatorDuplexCallback 

    [OperationContract(IsOneWay = true)] 
    void Equals(double result); 
    [OperationContract(IsOneWay = true)] 
    void Equation(string eqn); 

4.由于回话是必须的,那么在契约实现的时候也要加上一个特性

  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]

public class Service1 : IService1 
   { 
       double result; 
       string equation; 
       ICalculatorDuplexCallback callback = null;

       public Service1() 
       { 
           result = 0.0D; 
           equation = result.ToString(); 
           callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>(); 
       }

       public void Clear() 
       { 
           callback.Equation(equation + " = " + result.ToString()); 
           result = 0.0D; 
           equation = result.ToString(); 
       }

       public void AddTo(double n) 
       { 
           result += n; 
           equation += " + " + n.ToString(); 
           callback.Equals(result); 
       }

       public void SubtractFrom(double n) 
       { 
           result -= n; 
           equation += " - " + n.ToString(); 
           callback.Equals(result); 
       }

       public void MultiplyBy(double n) 
       { 
           result *= n; 
           equation += " * " + n.ToString(); 
           callback.Equals(result); 
       }

       public void DivideBy(double n) 
       { 
           result /= n; 
           equation += " / " + n.ToString(); 
           callback.Equals(result); 
       } 
}

5.接着在项目中添加一个控制台程序,添加服务。服务会报异常

System.InvalidOperationException: 协定需要会话,但是绑定“BasicHttpBinding”不支持它或者因配置不正确而无法支持它。 
   在 System.ServiceModel.Description.DispatcherBuilder.BuildChannelListener(StuffPerListenUriInfo stuff, ServiceHostBase serviceHost, Uri listenUri, ListenUriMode listenUriMode, Boolean supportContextSession, IChannelListener& result) 
   在 System.ServiceModel.Description.DispatcherBuilder.InitializeServiceHost(ServiceDescription description, ServiceHostBase serviceHost) 
   在 System.ServiceModel.ServiceHostBase.InitializeRuntime() 
   在 System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout) 
   在 System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout) 
   在 Microsoft.Tools.SvcHost.ServiceHostHelper.OpenService(ServiceInfo info)

需要把服务端配置文件中改一下:

<system.serviceModel>
<services>
<service name="WcfService1.Service1" behaviorConfiguration="WcfService1.Service1Behavior">

<!-- Service Endpoints -->
<!-- 除非完全限定,否则地址将与上面提供的基址相关 -->
<endpoint address="" binding="wsDualHttpBinding" contract="WcfService1.IService1">
<!--
部署时,应删除或替换下列标识元素,以反映
用来运行所部署服务的标识。删除之后,WCF 将
自动推断相应标识。
-->
<identity>
<dns value="http://www.mamicode.com/localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- 元数据交换终结点供相应的服务用于向客户端做自我介绍。 -->
<!-- 此终结点不使用安全绑定,应在部署前确保其安全或将其删除-->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WcfService1.Service1Behavior">
<!-- 为避免泄漏元数据信息,
请在部署前将以下值设置为 false -->
<serviceMetadata httpGetEnabled="False" httpsGetEnabled="False"/>
<!-- 要接收故障异常详细信息以进行调试,
请将以下值设置为 true。在部署前设置为 false
以避免泄漏异常信息-->
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

6.在控制台端,添加服务引用,实现服务定义的ICalculatorDuplexCallback接口(该接口自动生成的对应到服务引用中的IService1Callback)

public class CallbackHandler : IService1Callback 
  { 
      public void Equals(double result) 
      { 
          Console.WriteLine("Result({0})", result); 
      }

      public void Equation(string eqn) 
      { 
          Console.WriteLine("Equation({0})", eqn); 
      } 
  }

7.在main函数中,去调用服务

           InstanceContext instanceContext = new InstanceContext(new CallbackHandler());

            // Create a client 
            ServiceReference1.Service1Client client = new ServiceReference1.Service1Client(instanceContext);

            Console.WriteLine("Press <ENTER> to terminate client once the output is displayed."); 
            Console.WriteLine();

            // Call the AddTo service operation. 
            double value = http://www.mamicode.com/100.00D;
            client.AddTo(value);

            // Call the SubtractFrom service operation. 
            value = http://www.mamicode.com/50.00D;
            client.SubtractFrom(value);

            // Call the MultiplyBy service operation. 
            value = http://www.mamicode.com/17.65D;
            client.MultiplyBy(value);

            // Call the DivideBy service operation. 
            value = http://www.mamicode.com/2.00D;
            client.DivideBy(value);

            // Complete equation 
            client.Clear();

            Console.ReadLine();

            //Closing the client gracefully closes the connection and cleans up resources 
            client.Close();

8.运行结果

image