WCF实现双工服务及客户端调用

请求-响应通信是最常规的用于客户端与服务之间信息交换的模式。通信由客户端发起,之后服务将响应消息发送给客户端。这种模式有一个弊端就是,服务总是被动的提供响应。假如服务需要给客户端发出一个通知或者警报,请求-响应这种单工模式就无法满足需求了。
这次要说的就是双工通信模式,该模式下服务可以向任一方发送未经请求的消息。当然双工通信也可以是单向的。
下面我们来看看其服务端是如何实现的。

    //这里定义服务接口和回调函数接口
    [ServiceContract(CallbackContract =typeof(IClientCallback))]
    public interface IService1
    {

        [OperationContract(IsOneWay =true)]
        void RegisterContract(string price);
    }

    public interface IClientCallback
    {
        [OperationContract(IsOneWay =true)]
        void PriceUpdate(string ticker, double price);
    }
    
    //先实现服务接口
    public class Service1 : IService1
    {
        public static Hashtable workers = new Hashtable();
        public void RegisterContract(string ticker)
        {
            Worker w = null;
            if (!workers.ContainsKey(ticker))
            {
                w = new Worker();
                w.ticker = ticker;
                w.workerProcess = new Update();
                w.workerProcess.ticker = ticker;
                workers[ticker] = w;
                //通过线程定时调用回调函数
                Thread t = new Thread(new ThreadStart(w.workerProcess.SendUpdateToClient));
                t.IsBackground = true;
                t.Start();
            }
            w = (Worker)workers[ticker];
            IClientCallback c = OperationContext.Current.GetCallbackChannel<IClientCallback>();
            lock (w.workerProcess.Callbacks)
            {
            	//给回调函数列表增加任务
                w.workerProcess.Callbacks.Add(c);
            }
        }
    }
    
    public class Worker
    {
        public string ticker;
        public Update workerProcess;
    }
    public class Update
    {
        public string ticker;

        public List<IClientCallback> Callbacks = new List<IClientCallback>();

        public void SendUpdateToClient()
        {
            Random p = new Random();
            while (true)
            {
                Thread.Sleep(5000);
                lock (Callbacks)
                {
                    foreach (IClientCallback c in Callbacks)
                    {
                        try
                        {
                        	//在这里对列表中存在的客户端发起回调
                            c.PriceUpdate(ticker, 100.00 + p.NextDouble());
                            LogOp.WriteLogFile(ticker+":" + 100.00 + p.NextDouble());
                        }
                        catch (Exception ex)
                        {
                            LogOp.WriteLogFile("SendUpdateToClient出错:" + ex.Message);
                        }
                    }
                }
            }
        }
    }

当然在配置中也需要应用wsDualHttpBinding的模式,下面是完整的配置。

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

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="" name="双工操作.Service1">
        <endpoint address="" binding="wsDualHttpBinding" contract="双工操作.IService1" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <protocolMapping>
        <add binding="wsDualHttpBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <!--
        若要在调试过程中浏览 Web 应用程序根目录,请将下面的值设置为 True。
        在部署之前将该值设置为 False 可避免泄露 Web 应用程序文件夹信息。
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

我这里是将服务托管在iis中。
在这里插入图片描述
下面我们来实现客户端:

static void Main(string[] args)
{
    InstanceContext site = new InstanceContext(new CallbackHandler());
    WCF.Service1Client service1Client = new WCF.Service1Client(site);
    service1Client.RegisterContract("MSFT");
    Console.WriteLine("启动成功");
    Console.ReadKey();
}
    public class CallbackHandler : WCF.IService1Callback
    {
        public void PriceUpdate(string ticker, double price)
        {
            Console.WriteLine("收到更新:"+ticker+price);
        }
    }

在客户端中需要继承IService1Callback接口,该接口可以供WCF服务端调用。以下是调用结果。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值