WCF双程操作(心跳)

        在写上一篇关于WCF的几种HelloWorld的写法时,我纯粹是学习语法,想对WCF有个最初的认识。进过一个多月项目的接触,似乎又明白了一些。项目中运用WCF框架实现总公司对子公司的服务器以及数据库的扫描监控(监控子公司是否正常,子公司定期给总公司发送受监控的数据),然后总公司对子公司的数据进行一些记录处理,最后再反馈到子公司(总公司回发数据给子公司)。归结起来就是服务端和客户端相互定期通信,也就是WCF中双程操作。这里主要介绍心跳技术。

        每当客户端给服务端发送消息时,服务端在接收到消息后,给客户端反馈一条消息(称为回调操作),而这个反馈消息不需要考虑客户端是否收到这个反馈消息。

        本文将公司的项目抽象成一个简单例子,例子展示如何实现服务端与客户端的交互。

       (可以点此下载先看效果)

一、服务端

        首先写服务契约

    [ServiceContract(CallbackContract = typeof(IWCFServiceCallBack))]
    public interface IWCFService
    {
        //操作契约
        [OperationContract]
        string OperationInfo(string name);
    }

       注:CallbackContract= typeof(IWCFServiceCallBack)表示服务端接收到客户端的消息时给客户的响应(即回调操作),IWCFServiceCallBack即为回调契约,定义如下:

    public interface IWCFServiceCallBack
    {
        //操作契约
        [OperationContract(IsOneWay = true)]
        void FeedBack(string info);
    }

       注:1.回调服务契约,由于回调方法在客户端执行,因此无须添加 ServiceContract特性。2.对于成功后回调反馈操作,服务器无须获取其返回信息,因此添加 IsOneWay=true 特性。

       接着,服务端实现契约:

    public class WCFService : IWCFService
    {
        //获取当前操作客户端对象实例
        IWCFServiceCallBack callback
           = OperationContext.Current.GetCallbackChannel<IWCFServiceCallBack>();
       //实现接口定义的方法(在服务端运行)
         public string OperationInfo(string clientPCName)
        {
            Console.WriteLine("收到客户端的连接消息消息:{0}  {1}", DateTime.Now, clientPCName);
            callback.FeedBack("进过分析后的用户名" + clientPCName.Split('-')[0]);
            //这边可以返回任何客户端需要的信息//如果客户端不需要信息可以将此函数设为void返回类型
              return "客户端连接正常";
        }
    }

二、宿主,主要工作就是开启服务

        配置文件如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>   
   <service   behaviorConfiguration="WCFService.WCFServiceBehavior" 
                 name="Service0413.WCFService">
        <endpoint
          address="net.tcp://localhost:9000/WCFService"
          binding="netTcpBinding"
          contract="Service0413.IWCFService">
        </endpoint>
        <host>
          <baseAddresses>
            <!--这里的baseAddress是客户端服务引用的URI-->
            <add baseAddress="http://localhost:9090/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="WCFService.WCFServiceBehavior">
          <!--为了可以通过URI引用服务,这里需设置httpGetEnabled为true-->
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

        寄宿宿主:

    //服务宿主就干一件事:打开服务
    class Host
    {
        static void Main(string[] args)
        {
            //回调服务WCFServiceCallBack
            ServiceHost host = new ServiceHost(typeof(Service0413.WCFService));
            try
            {
                //判断是否以及打开连接,如果尚未打开,就打开侦听端口
                if (host.State != CommunicationState.Opening)
                host.Open();
                //显示运行状态
                Console.WriteLine("ServiceHost is runing! and state is {0}", host.State);
                Console.Read();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
            finally
            {
                host.Close();
            }
        }
    }

三、客户端:

        首先要实现回调的契约接口(通俗点将就是服务端接收到客户端消息后给客户端发聩信息,在客户端执行):

    /// <summary>要实现回调的契约接口
    /// </summary>
    public class WCFCallback : Service2012.IWCFServiceCallback
    {
        public void FeedBack(string info)
        {
            Console.WriteLine("服务器已经收到您的消息!消息内容:" + info);
        }
    }

       最后是入口函数部分(由于源代码上传的较早,这个在下载源代码里,稍有不同,可以自行替换此类)。

   public class Client
    {
        //获得客户端的计算机名(实际可以扩展到获取客户端的一切想要的数据)
         private static string clientName = Environment.MachineName;
        private static Service2012.IWCFServiceCallback callBack = new WCFCallback();
        private static InstanceContext context = new InstanceContext(callBack);
        private static Service2012.WCFServiceClient WCFServiceCallBackClientProxy =
                       new WCFServiceClient(context, "NetTcpBinding_IWCFService");
        static void Main(string[] args)
        {
            System.Timers.Timer timer = new System.Timers.Timer(2000);
            //绑定定期自动执行的操作
              timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            timer.Enabled = true;
            string s=Console.ReadLine();
            Console.WriteLine(s);
        }
        private static void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            string operateInfo = WCFServiceCallBackClientProxy.OperationInfo(clientName);
            Console.WriteLine(operateInfo);
        }
    }

       至此完成,本例没有进行异常处理,请注意先运行服务端,再运行客户端。

        学习一个多月也遇到了一些问题,有些值得分享:         

        1.当在类库中添加了服务引用时,只会自动生成类库中的配置文件,其他程序引用该DLL时注意将配置文件的信息也添加进去。

        2.WCF的测试可以先添加断点,开启服务,通过调试--附加到进程进行测试。

        3.对于服务端的参数是List时,在客户端有两种情况,当是自己实现手动实现通道时客户端参数还是List的,而当客户端是通过引用自动生成时,参数就相应的变成了数组,此时只要通过ToArray()方法将其改为数组即可(当时遇到时,虽然看到了里面参数是数组,但我以为是哪里弄错了,重写了个例子发现还是一样,一问项目组的前辈,原来这是正常的情况,具体原因尚不知道,暂且记录,还望了解者指点)。

        后记:写的还比较简单,自我感觉只是授之以鱼,而没有授之以渔,本人刚学,认识有限,很多理解的可能还只停留在鱼的地步。

        源码下载

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值