WCF服务编程-契约回调

22 篇文章 0 订阅

双向通讯是这样的一种机制,就是服务端与客户端的身份是可换的,服务示例可以回调客户端的操作,当一个服务契约被定义在服务端的时候,有时候我们的业务逻辑要求我门进行相应的回调操作。标准的服务契约定义了能够被客户端调用的服务操作。回调契约定义了能够被服务端调用的客户端操作。因此,客户端必须具有实现回调契约的义务和宿主回调对象的能力。每当客户端调用具有回调操作的服务端示例操作的时候,客户端必须提供足够的信息以使服务端能够寻址到客户端并执行相应的回调操作。[引用]

接下来我们就来做这样的一个场景,这个场景也是从网上看的。WCF服务端提供一个加法的服务,客户端调用服务端的服务之后,服务端回调客户端的显示方法最后将结果显示在客户端界面。下面是运行的效果,源码在此下载

image

在WCF的默认的绑定中WSDualHttpBinding是一个安全且可互操作的绑定。适用于双工服务协定或通过 SOAP 媒介进行的通信。本示例就是基于此绑定来实现的。为在编程中多应用些WCF编程的技术,服务端采用代码来创建服务端承载。

 

第一步 创建标准契约和回调契约

回调契约,用于在客户端显示结果信息 

[ServiceContract(Namespace="http://www,cbcye.com/wcf/Callback/)]
public interface ICalculatorCallback
{
    [OperationContract]
    void ShowResult(double x, double y, double result);

标准契约,声明了回调契约的类型 

[ServiceContract(CallbackContract = typeof(ICalculatorCallback))]
public interface IDuplexCalculator
{
    [OperationContract]
    void Add(double x, double y);

第二步 在服务端实现标准契约 

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public  class DuplexCalculatorService:IDuplexCalculator


    IDuplexCalculator Members#region IDuplexCalculator Members 

    public void Add(double x, double y)
    {
        double result = x + y;
        //调用 GetCallbackChannel<(Of <(T>)>) 属性以获取通道,使用该通道可以调用调用服务的客户端实例的操作。
        ICalculatorCallback callBack = OperationContext.Current.GetCallbackChannel<ICalculatorCallback>();
        callBack.ShowResult(x, y, result);
    }
 

    #endregion

}
 

第三步 创建服务端承载  
class Program
     {
        static void Main(string[] args)
        {
            HostCalculatorService();
        }
 
        static void HostCalculatorService()
        {
            Uri dualUri = new Uri("http://localhost:7788/cbcye/Calculator%22);
            //向HOST中添加BaseAddress
            using (ServiceHost calculatorServiceHost = new ServiceHost(typeof(DuplexCalculatorService), dualUri))
            {
                //WSDualHttpBinding适用于双工服务协定或通过 SOAP 媒介进行的通信。
                WSDualHttpBinding wsDualHttpBinding = new WSDualHttpBinding();
                //添加服务绑定和服务契约
                calculatorServiceHost.AddServiceEndpoint(typeof(IDuplexCalculator), wsDualHttpBinding, string.Empty); 

                //绑定服务行为
                ServiceMetadataBehavior behavior = calculatorServiceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
                {
                    if (behavior == null)
                    {
                        behavior = new ServiceMetadataBehavior();
                        behavior.HttpGetEnabled = true;
                        calculatorServiceHost.Description.Behaviors.Add(behavior);
                    }

                    else
                    {
                        behavior.HttpGetEnabled = true;
                    }

                }
 

                //启动事件
                calculatorServiceHost.Opened += delegate
                {
                    Console.WriteLine("Calculator Service has begun to listen   on "+ dualUri.ToString());
                }


                calculatorServiceHost.Open();
                Console.Read();
            }

        }

    }
 

第四步 在客户端实现回调契约
class CalculatorCallbackHandler:ICalculatorCallback
{
     #region ICalculatorCallback Members 

     public  void ShowResult( double x,  double y,  double result)
    {
        Console.WriteLine( " x + y = {2} (x = {0} , y = {1}) ", x, y, result);
    } 

     #endregion


第五步 实现客户端代理 
class ClientProxy:ClientBase<IDuplexCalculator>,IDuplexCalculator


     public ClientProxy(InstanceContext callbackInstance)
       :  base(callbackInstance)
    { } 

     #region IDuplexCalculator Members 

     public  void Add( double x,  double y)
    {
         this.Channel.Add(x, y);
    }
     #endregion


第六步 客户端调用

程序代码

class Program
{
    static void Main(string[] args)
    {
        try
        {
            InvocateDuplexCalculator();
        }

        catch (Exception exp)
        {
            Console.WriteLine("[Error] " + exp.Message);
        }
 

        Console.Read();
    }
 
    static void InvocateDuplexCalculator()
    {
        CalculatorCallbackHandler callbackHandler = new CalculatorCallbackHandler(); 

        using (ClientProxy calculator = new ClientProxy(new InstanceContext(callbackHandler)))
        {
            Console.WriteLine("Begin to invocate duplex calculator ");
            calculator.Add(8586);
            calculator.Close();
        }

    }

}
 


配置文件

由于使用WSDualHttpBinding绑定执行回调时,需要开通两个HTTP通道,一个用于服务,一个用于回调。因此需要配置两个HTTP地址。 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <client>
      <!--bindingConfiguration - 指定一个binding的配置名称,跟<bindings>下面同类<binding>的name匹配-->
      <endpoint name="SubscriptionService"
                      address
="http://localhost:7788/cbcye/Calculator%22
                      binding="
wsDualHttpBinding"
                      bindingConfiguration
="wsDualHttpBinding_DuplexCalculator"
                      contract
="Cbcye.Contract.IDuplexCalculator"
            
/>
    </client>
    <bindings>
      <!-- 指定一个或多个系统预定义的binding,比如<basicHttpBinding>,当然也可以指定自定义的customBinding,
             然后在某个指定的binding下建立一个或多个配置,以便被Endpoint来使用这些配置 
-->
      <wsDualHttpBinding>
        <binding
                    
name="wsDualHttpBinding_DuplexCalculator"
                    clientBaseAddress
="http://localhost:7799/cbcye/Calculator%22
          />
      </wsDualHttpBinding>
    </bindings>
  </system.serviceModel>
</configuration> 


经过验证的服务配置文件

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

    <startup> 

        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />

    </startup>

  <system.serviceModel>

    <services>

      <service name="ConsoleApplication1.CMyHello">

        <host>

          <baseAddresses>

            <add baseAddress="http://localhost:12345"/>

          </baseAddresses>

        </host>

        <endpoint address="" binding="basicHttpBinding" contract="MyInterLayer.IMyHello">

        </endpoint>

      </service>

    </services>

  </system.serviceModel>

</configuration>


客户配置:

  <system.serviceModel>
    <client>
      <!--bindingConfiguration - 指定一个binding的配置名称,跟<bindings>下面同类<binding>的name匹配-->
      <endpoint name="ClassLibrary1.CServer"
                      address="http://localhost:12345" binding="wsDualHttpBinding"
                      contract="ClassLibrary1.IServer"
            />
    </client>
  </system.serviceModel>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值