博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WCF 服务端+客户端动态调用
阅读量:4308 次
发布时间:2019-06-06

本文共 42376 字,大约阅读时间需要 141 分钟。

最近在写WCF服务相关代码,把项目中用到的通讯框架做了下整理,以备以后自己记忆。

WCF服务端:

包含契约定义:WCF.Contract、契约实现:WCF.Service 以及宿主主程序:WcfServerHost

本DEMO 为了为了演示,只定义了一个常用的计算算法和一个双向通讯的问号类

一、契约类工程 WCF.Contract

单向通讯契约:ICalculatorService

using System;using System.Collections.Generic;using System.Linq;using System.ServiceModel;using System.Text;using System.Threading.Tasks;namespace WCF.Contract{    ///     /// 用户操作接口,提供算法运行    ///     [ServiceContract]    public interface ICalculatorService    {        [OperationContract]        double Add(double x, double y);        [OperationContract]        double Subtract(double x, double y);        [OperationContract]        double Multiply(double x, double y);        [OperationContract]        double Divide(double x, double y);    }}
View Code

双向通讯类契约:IDuplexMessageService

using System;using System.Collections.Generic;using System.Linq;using System.ServiceModel;using System.Text;using System.Threading.Tasks;namespace WCF.Contract{    [ServiceContract(CallbackContract = typeof(IDuplexMessageCallBack))]    public interface IDuplexMessageService    {        ///         /// 订阅服务,当回调产生时会对客户端进行推送        ///         [OperationContract(IsOneWay = true)]        void SubscribeAlarm();        ///         /// 取消订阅,取消之后不推送        ///         [OperationContract(IsOneWay = true)]        void UnSbuscribeAlarm();        ///         /// 客户端登录服务端        ///         /// 客户端登录服务端        [OperationContract(IsOneWay = true)]        void Login(string username);    }}
View Code

客户端callback:IDuplexMessageCallBack

using System;using System.Collections.Generic;using System.Linq;using System.ServiceModel;using System.Text;namespace WCF.Contract{    ///     /// 功    能:客户端回调契约    /// 创 建 人:     /// 创建时间:    ///     [ServiceContract]    public interface IDuplexMessageCallBack    {        ///         /// 服务端返回给客户的问号信息        ///         /// 如果需要返回数据,使用json格式        [OperationContract]        void Greet(string msg);        ///         /// 服务端返回给客户的离开信息        ///         /// 如果需要返回数据,使用json格式        [OperationContract]        void Leave(string ip);    }}
View Code

二、契约实现工程 WCF.Service

单向通讯类工程实现类:CalculatorService

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using WCF.Contract;namespace WCF.Service{    ///     /// 功    能:算法单向通道管理服务类型    /// 创 建 人:龚安川    /// 创建时间:2017-02-24    ///     public class CalculatorService : ICalculatorService    {              public double Add(double x, double y)        {            return x + y;        }        public double Subtract(double x, double y)        {            return x - y;        }        public double Multiply(double x, double y)        {            return x * y;        }        public double Divide(double x, double y)        {            return x / y;        }    }}
View Code

双向通讯类实现:DuplexMessageService

using System;using System.Collections.Generic;using System.Linq;using System.ServiceModel;using System.ServiceModel.Channels;using System.Text;using System.Threading.Tasks;using WCF.Contract;namespace WCF.Service{    ///     /// 功    能:DuplexMessageService双向通道管理服务类型-处理客户端事件回调    /// 创 建 人:龚安川    /// 创建时间:2017-02-24    ///     [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = true, ConcurrencyMode = ConcurrencyMode.Multiple)]    public class DuplexMessageService : IDuplexMessageService    {        #region [变量定义]        ///         /// 客户端回调通道字典        /// key:IP        /// value:回调通道        ///         private Dictionary
Client_Callback_Dic = new Dictionary
(); ///
/// 客户端回调字典锁 /// private static object ClientLock = new object(); #endregion //构造函数 public DuplexMessageService() { } #region IDuplexMessageService 成员 ///
/// 订阅报警,当报警产生时会对客户端进行推送 /// ///
客户端唯一标识符
public void SubscribeAlarm() { RemoteEndpointMessageProperty endpoint = OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty; string ip = endpoint.Address; lock (ClientLock) { if (Client_Callback_Dic.ContainsKey(ip)) { if (!Client_Callback_Dic[ip].Equals(OperationContext.Current.GetCallbackChannel
())) { /*如果通道和原来的不一样,客户端重启了*/ Client_Callback_Dic[ip] = OperationContext.Current.GetCallbackChannel
(); try { //客户端报警推送 //Client_Callback_Dic[ip].Leave(ip); } catch { } } } else { Client_Callback_Dic.Add(ip, OperationContext.Current.GetCallbackChannel
()); try { //客户端报警推送 //Client_Callback_Dic[ip].Leave(ip); } catch { } } } } ///
/// 取消订阅,取消之后不推送 /// ///
客户端唯一标识符 public void UnSbuscribeAlarm() { RemoteEndpointMessageProperty endpoint = OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty; string ip = endpoint.Address; lock (ClientLock) { if (Client_Callback_Dic.ContainsKey(ip)) { Client_Callback_Dic.Remove(ip); return; } } } ///
/// 客户端发往服务端加入信息 /// ///
客户端唯一标识符 ///
客户端发来的信息,如果需要传送信息使用json格式传送 public void Login(string username) { RemoteEndpointMessageProperty endpoint = OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty; string ip = endpoint.Address; lock (ClientLock) { IDuplexMessageCallBack callBack = OperationContext.Current.GetCallbackChannel
(); if (Client_Callback_Dic.ContainsKey(ip)) { if (!Client_Callback_Dic[ip].Equals(callBack)) { Client_Callback_Dic[ip] = OperationContext.Current.GetCallbackChannel
(); } } else { Client_Callback_Dic.Add(ip, callBack); } try { //服务端调用客户端问号信息 Client_Callback_Dic[ip].Greet("欢迎您:" + ip); } catch { } } } #endregion }}
View Code

三、WCF宿主程序 WcfServerHost 直接建立的控制台程序

服务管理类:ServerManagement

using System;using System.Collections.Generic;using System.Linq;using System.Management;using System.ServiceProcess;using System.Text;using System.Threading;using System.Threading.Tasks;namespace WcfServerHost{    ///     /// 功    能:WCF服务控制类    /// 创 建 人:龚安川    /// 创建时间:2017-02-24    ///     public class ServerManagement    {        ///         /// 服务开启        ///         public static void Start()        {            new Thread(() =>            {                log4net.ILog log = log4net.LogManager.GetLogger(typeof(ServerManagement));                try                {                    ConnectionOptions coOptions = new ConnectionOptions();                    coOptions.Impersonation = ImpersonationLevel.Impersonate;                    // CIMV2 is a namespace that contains all of the core OS and hardware classes.                    // CIM (Common Information Model) which is an industry standard for describing                    // data about applications and devices so that administrators and software                    // management programs can control applications and devices on different                    // platforms in the same way, ensuring interoperability across a network.                    ManagementScope mgmtScope = new ManagementScope(@"root\CIMV2", coOptions);                    mgmtScope.Connect();                    ManagementObject wmiService;                    wmiService = new ManagementObject("Win32_Service.Name='" + "Pisservice" + "'");                    ManagementBaseObject InParam = wmiService.GetMethodParameters("Change");                    InParam["DesktopInteract"] = true;                    wmiService.InvokeMethod("Change", InParam, null);                }                catch (Exception ex)                {                    log.Error(ex);                }                #region [验证启动关联服务]                ////获取系统服务                //ServiceController[] services = ServiceController.GetServices();                //ServiceController mysqlService = null;                //foreach (ServiceController sc in services)                //{                //    if (sc.ServiceName.ToLower().Equals("mysql") || sc.ServiceName.ToLower().Equals("mariadb"))                //    {                //        mysqlService = sc;                //        break;                //    }                //}                //if (mysqlService == null)                //    throw new Exception("没有找到mysql服务");                //log.Debug(mysqlService.Status.ToString());                //if (mysqlService.Status == ServiceControllerStatus.Stopped)                //{                //    for (int i = 1; i < 1000; i++)                //    {                //        log.Debug(i);                //        if (mysqlService.Status != ServiceControllerStatus.Stopped)                //        {                //            break;                //        }                //        if (i % 10 == 0)                //        {                //            try                //            {                //                log.Debug(i + "start");                //                mysqlService.Start();                //            }                //            catch (Exception ex) { log.Debug(ex); }                //        }                //        System.Threading.Thread.Sleep(1000);                //    }                //}                #endregion                System.Threading.Thread.Sleep(20000);   //给数据库加载时间                //初始化缓存服务                //new ServiceCacheManagement().InitCache();                //创建本地服务                ServiceHostFactory.Instance.StartAllService();                ////开启级联监听服务                //AnalysisCascade.GetInstance().StartAnalysis();                ////开启广播监听服务                //AnalysisBroadCast.GetInstance().StartAnalysis();                //BroadCast.GetInstance().StartListen();                ////BroadCastTranspond.GetInstance().Start();                ////BroadCastCascade.GetInstance().Start();                ////CorrectTime.GetInstance().Start();                //Battery.GetInstance().CheckBattery();                //DetectComputerDrive.GetInstance().DetectDrive();                //开启日志清理服务                //ClearLogManagement.StartClear();            }) { IsBackground = true }.Start();        }        ///         /// 服务停止        ///         public static void Stop()        {            //AnalysisBroadCast.GetInstance().StopAnalysis();            //ClearLogManagement.StopClear();            //CorrectTime.GetInstance().Stop();            //BroadCast.GetInstance().StopListen();            //AnalysisCascade.GetInstance().StopAnalysis();            //BroadCastTranspond.GetInstance().Stop();            //BroadCastCascade.GetInstance().Stop();            ServiceHostFactory.Instance.StopAllService();        }    }}
View Code

服务工厂类:ServiceHostFactory,

using log4net;using System;using System.Collections.Generic;using System.Configuration;using System.Linq;using System.Reflection;using System.ServiceModel;using System.ServiceModel.Configuration;using System.Text;using System.Threading.Tasks;using WCF.Service;namespace WcfServerHost{    ///     /// 功    能:WCF服务工厂类    /// 创 建 人:龚安川    /// 创建时间:2017-02-24    ///     public class ServiceHostFactory    {        #region [变量定义]        ///         /// 日志管理对象        ///         private ILog log = LogManager.GetLogger(typeof(ServiceHostFactory));        ///         /// 此处必须用单例,防止多次开启导致异常        ///         private static ServiceHostFactory instance = null;        ///         /// 对象锁        ///         private static object padlock = new object();        ///         /// 服务列表        ///         private Dictionary
m_HostDic; ///
/// 服务类型集合 /// private List
Services = new List
(); ///
/// 标识服务是否开启 /// private bool isOpen = false; #endregion public static ServiceHostFactory Instance { get { if (instance == null) { lock (padlock) { if (instance == null) instance = new ServiceHostFactory(); } } return instance; } } private ServiceHostFactory() { m_HostDic = new Dictionary
(); //初始化服务 InitServices(); GetCfg(); } ///
/// 析构函数 /// ~ServiceHostFactory() { StopAllService(); } #region [公开方法] ///
/// 开启所有服务 /// public void StartAllService() { lock (padlock) { try { if (isOpen) return; if (m_HostDic == null) return; var keys = m_HostDic.Keys.ToList(); foreach (var serviceType in keys) { var host = m_HostDic[serviceType]; if (host == null) m_HostDic[serviceType] = CreatHost(serviceType); var state = m_HostDic[serviceType].State; if (state == CommunicationState.Faulted) { m_HostDic[serviceType].Abort(); m_HostDic[serviceType] = CreatHost(serviceType); } if (state == CommunicationState.Closed || state == CommunicationState.Closing) m_HostDic[serviceType] = CreatHost(serviceType); if (!(state == CommunicationState.Opened || state == CommunicationState.Opening)) m_HostDic[serviceType].Open(); }//end foreach isOpen = true; //LogManagent.Log("开启服务", Util.PISLOG_TYPE_RUNING, "服务启动成功"); } catch (Exception ex) { //LogManagent.Log("开启服务", Util.PISLOG_TYPE_RUNING, "服务启动失败"); log.Error(ex); StopAllService(); throw ex; } } } ///
/// 关闭所有服务 /// public void StopAllService() { if (m_HostDic == null) return; var keys = m_HostDic.Keys.ToList(); foreach (var serviceType in keys) { var host = m_HostDic[serviceType]; if (host == null) continue; try { host.Close(TimeSpan.FromSeconds(5)); } catch { host.Abort(); } } //LogManagent.Log("关闭服务", Util.PISLOG_TYPE_RUNING, "服务关闭成功"); isOpen = false; } #endregion #region [私有方法] //初始计划服务 private void InitServices() { Services.Clear(); Services.Add(typeof(CalculatorService)); Services.Add(typeof(DuplexMessageService)); } // 从配置文件中读取需要开启的服务列表 private void GetCfg() { //循环所有服务类型 foreach (Type t in Services) { ServiceHost host = CreatHost(t); m_HostDic[t] = host; } } //创建当前类型的服务 private ServiceHost CreatHost(Type svcType) { ServiceHost host = new ServiceHost(svcType); //调试时打开IncludeExceptionDetailInFaults,可将异常传递到客户端; ServiceBehaviorAttribute behavior = host.Description.Behaviors.Find
(); behavior.IncludeExceptionDetailInFaults = true; return host; } #endregion }}
View Code

配置文件App.config,利用system.serviceModel 节点,动态配置需要管理的服务

View Code

至此,一个WCF服务端就实现好了

WCF客户端

包含WCF客户端实现类:WCF.Client、双向通讯CallBackHandle:WCF.Duplex 以及演示程序:WcfClient

 

一、客户端代理工厂: WCF.Client

 WCF客户端类:WCFClient

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using WCF.Contract;namespace WCF.Client{    ///     /// 功    能:WCFClient 对象    /// 创 建 人:龚安川    /// 创建时间:2017-02-24    ///     public class WCFClient    {        #region [变量定义]        #region [Static]        ///         /// WCF客户端对象-单例模式        ///         static WCFClient instance = null;        static object padlock = new object();        ///         /// 实例化客户端代理-单例模式;        ///         public static WCFClient Instance        {            get            {                if (instance == null)                {                    lock (padlock)                    {                        if (instance == null)                        {                            instance = new WCFClient();                        }                    }                }                return instance;            }        }        #endregion        ///         /// 服务终结点集合对象        ///         private Dictionary
_EndpointNameDic; #endregion private WCFClient() { InitEndpointNameDic(); } #region [公开方法] ///
/// 获取WCF客户端代理-单向通讯 /// ///
契约类型
///
public T GetService
() { return ServiceProxyFactory.Create
(_EndpointNameDic[typeof(T).Name]); } ///
/// 获取WCF客户端代理-双向通讯 /// ///
///
///
public T GetService
(object context) { return ServiceProxyFactory.Create
(context, _EndpointNameDic[typeof(T).Name]); } #endregion #region [私有方法] //初始化终结点集合 private void InitEndpointNameDic() { _EndpointNameDic = new Dictionary
(); _EndpointNameDic.Add(typeof(ICalculatorService).Name, EndpointNames.CalculatorService); _EndpointNameDic.Add(typeof(IDuplexMessageService).Name, EndpointNames.DuplexMessageService); } #endregion }}
View Code

服务代理工厂类:ServiceProxyFactory

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace WCF.Client{       ///     /// 功    能:服务代理工厂    /// 创 建 人:龚安川    /// 创建时间:XXXX    ///     public static class ServiceProxyFactory    {        #region [公开方法]        ///         /// 创建到指定终结点地址的指定类型的通道;        ///         /// 
由通道工厂生成的通道类型
/// 用于终结点的配置名称 ///
public static T Create
(string endpointName) { if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException("endpointName"); } //通过自定义的RealProxy创建TransparentProxy供客户端代码调用,统一管理调用异常记录 return (T)(new ServiceRealProxy
(endpointName).GetTransparentProxy()); } ///
/// 创建到指定终结点地址的指定类型的通道; /// 在服务和客户端上的回调实例之间创建双工通道; /// ///
由通道工厂生成的通道类型
///
客户端用以侦听来自所连接服务的消息 ///
用于终结点的配置名称 ///
public static T Create
(object callbackObject, string endpointName) { if (callbackObject == null) { throw new ArgumentNullException("callbackObject"); } if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException("endpointName"); } //通过自定义的RealProxy创建TransparentProxy供客户端代码调用,统一管理调用异常记录 return (T)new DuplexServiceRealProxy
(callbackObject, endpointName).GetTransparentProxy(); } ///
/// 创建到指定终结点地址的指定类型的通道; /// 在服务和客户端上的回调实例之间创建双工通道; /// 调用结束后根据指定决定是否立即释放通道; /// ///
由通道工厂生成的通道类型
///
客户端用以侦听来自所连接服务的消息 ///
用于终结点的配置名称 ///
是否立即释放 ///
public static T Create
(object callbackObject, string endpointName, bool immediateRelease) { if (callbackObject == null) { throw new ArgumentNullException("callbackObject"); } if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException("endpointName"); } return (T)new DuplexServiceRealProxy
(callbackObject, endpointName, immediateRelease).GetTransparentProxy(); } #endregion }}
View Code

自定义单通道真实代理:ServiceRealProxy

using System;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Runtime.Remoting.Messaging;using System.Runtime.Remoting.Proxies;using System.ServiceModel;using System.Text;using System.Threading.Tasks;namespace WCF.Client{    ///     /// 功    能:自定义单通道真实代理    /// 创 建 人:龚安川    /// 创建时间:XXXX    /// 说明:RealProxy中加入异常捕获、记录日志等非业务逻辑代码    ///      这些代码在每次调用服务端方法时都会被调用    ///     internal class ServiceRealProxy
: RealProxy { #region [变量定义] ///
/// 终结点名称 /// private string _endpointName; #endregion public ServiceRealProxy(string endpointName) : base(typeof(T)) { if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException("endpointName"); } this._endpointName = endpointName; } public override IMessage Invoke(IMessage msg) { T channel = ChannelFactoryCreator.Create
(this._endpointName).CreateChannel(); IMethodCallMessage methodCall = (IMethodCallMessage)msg; IMethodReturnMessage methodReturn = null; object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[]; methodCall.Args.CopyTo(copiedArgs, 0); try { object returnValue = methodCall.MethodBase.Invoke(channel, copiedArgs); methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall); (channel as ICommunicationObject).Close(); } catch (Exception ex) { if (ex.InnerException is CommunicationException || ex.InnerException is TimeoutException) { (channel as ICommunicationObject).Abort(); } //记录异常信息; StringBuilder message = new StringBuilder(); message.AppendLine(string.Format("An exception is throw when invoking {0}.{1} method.", channel.GetType().FullName, methodCall.MethodName)); if (ex.InnerException != null) { methodReturn = new ReturnMessage(ex.InnerException, methodCall); message.AppendLine(string.Format("Exception Type:{0}", ex.InnerException.GetType().AssemblyQualifiedName)); message.AppendLine(string.Format("Stack Trace:{0}", ex.InnerException.StackTrace)); } else { methodReturn = new ReturnMessage(ex, methodCall); message.AppendLine(string.Format("Exception Type:{0}", ex.InnerException.GetType().AssemblyQualifiedName)); message.AppendLine(string.Format("Stack Trace:{0}", ex.InnerException.StackTrace)); } message.AppendLine("Input Arguments:"); for (int i = 0; i < methodCall.InArgs.Length; i++) { message.AppendLine(string.Format("{0}={1}", methodCall.GetInArgName(i), methodCall.GetInArg(i))); } Debug.WriteLine(message); } return methodReturn; } }}
View Code

自定义双通道真实代理:DuplexServiceRealProxy

using System;using System.Collections;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Runtime.Remoting.Messaging;using System.Runtime.Remoting.Proxies;using System.ServiceModel;using System.Text;using System.Threading.Tasks;namespace WCF.Client{    ///     /// 功    能:自定义双工通道真实代理;     /// 创 建 人:龚安川    /// 创建时间:    ///     /// 
internal class DuplexServiceRealProxy
: RealProxy { #region [变量定义] ///
/// 通道集合 /// private static Hashtable channels = new Hashtable(); ///
/// 终结点名称 /// private string _endpointName; ///
/// 回调对象 /// private object _callbackObject; ///
/// 通道是否已释放 /// private bool _immediateRelease; #endregion public DuplexServiceRealProxy(object callbackObject, string endpointName, bool immediateRelease = false) : base(typeof(T)) { if (callbackObject == null) { throw new ArgumentNullException("callbackObject"); } if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException("endpointName"); } this._callbackObject = callbackObject; this._endpointName = endpointName; this._immediateRelease = immediateRelease; } #region [私有方法] private T GetChannel(string channelKey) { T channel = default(T); if (this._immediateRelease) { //重新创建代理通道 channel = DuplexChannelFactoryCreator.Create
(this._callbackObject, this._endpointName).CreateChannel(); } else { if (channels.ContainsKey(channelKey)) { //赋值当前通讯通道 channel = (T)channels[channelKey]; } //检测通道是否关闭或出错; if (channel != null) { var state = (channel as ICommunicationObject).State; if (state == CommunicationState.Closed || state == CommunicationState.Faulted)//通道已关闭或出错; { if (state == CommunicationState.Faulted) (channel as ICommunicationObject).Abort();//通道出错,强制关闭; channel = default(T); } } if (channel == null) { channel = DuplexChannelFactoryCreator.Create
(this._callbackObject, this._endpointName).CreateChannel(); lock (channels.SyncRoot) { channels[channelKey] = channel; } } } return channel; } #endregion public override IMessage Invoke(IMessage msg) { string channelKey = this._endpointName; //获取当前通道 T channel = GetChannel(channelKey); IMethodCallMessage methodCall = (IMethodCallMessage)msg; IMethodReturnMessage methodReturn = null; object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[]; methodCall.Args.CopyTo(copiedArgs, 0); try { object returnValue = methodCall.MethodBase.Invoke(channel, copiedArgs); methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall); if (this._immediateRelease) (channel as ICommunicationObject).Close(); } catch (Exception ex) { if (ex.InnerException is FaultException) { } else if (ex.InnerException is CommunicationException || ex.InnerException is TimeoutException) { (channel as ICommunicationObject).Abort(); lock (channels.SyncRoot) { channels[channelKey] = default(T); } } //记录异常信息; StringBuilder message = new StringBuilder(); message.AppendLine(string.Format("An exception is throw when invoking {0}.{1} method.", channel.GetType().FullName, methodCall.MethodName)); if (ex.InnerException != null) { methodReturn = new ReturnMessage(ex.InnerException, methodCall); message.AppendLine(string.Format("Exception Type:{0}", ex.InnerException.GetType().AssemblyQualifiedName)); message.AppendLine(string.Format("Stack Trace:{0}", ex.InnerException.StackTrace)); } else { methodReturn = new ReturnMessage(ex, methodCall); message.AppendLine(string.Format("Exception Type:{0}", ex.InnerException.GetType().AssemblyQualifiedName)); message.AppendLine(string.Format("Stack Trace:{0}", ex.InnerException.StackTrace)); } message.AppendLine("Input Arguments:"); for (int i = 0; i < methodCall.InArgs.Length; i++) { message.AppendLine(string.Format("{0}={1}", methodCall.GetInArgName(i), methodCall.GetInArg(i))); } Debug.WriteLine(message); } return methodReturn; } }}
View Code

单通道静态工厂类:ChannelFactoryCreator

using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.ServiceModel;using System.Text;using System.Threading.Tasks;namespace WCF.Client{    ///     /// 功    能:ChannelFactory单通道静态工厂类    /// 创 建 人:龚安川    /// 创建时间:XXXX    ///     internal static class ChannelFactoryCreator    {        ///         /// 通道工厂集合对象        ///         private static Hashtable channelFactories = new Hashtable();        ///         /// 通道创建        ///         /// 
契约类型
/// 终结点名称 ///
public static ChannelFactory
Create
(string endpointName) { if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException("endpointName"); } ChannelFactory
channelFactory = null; //判断当前终结点是否存在 if (channelFactories.ContainsKey(endpointName)) { //返回当前通道工厂 channelFactory = channelFactories[endpointName] as ChannelFactory
; } if (channelFactory == null) { //创建新的通道工厂 channelFactory = new ChannelFactory
(endpointName); //锁定通道工厂集合 lock (channelFactories.SyncRoot) { //更新当前通道终结点对象 channelFactories[endpointName] = channelFactory; } } return channelFactory; } }}
View Code

双通道静态工厂类:DuplexChannelFactoryCreator

using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.ServiceModel;using System.Text;using System.Threading.Tasks;namespace WCF.Client{    /// 功    能:DuplexChannelFactoryCreator双通道静态工厂类    /// 创 建 人:龚安川    /// 创建时间:XXXX    ///     internal static class DuplexChannelFactoryCreator    {        ///         /// 通道工厂集合对象        ///         private static Hashtable channelFactories = new Hashtable();        public static DuplexChannelFactory
Create
(object callbackObject, string endpointName) { if (callbackObject == null) { throw new ArgumentNullException("callbackObject"); } if (string.IsNullOrEmpty(endpointName)) { throw new ArgumentNullException("endpointName"); } DuplexChannelFactory
channelFactory = null; //判断当前终结点是否存在 if (channelFactories.ContainsKey(endpointName)) { //返回当前通道工厂 channelFactory = channelFactories[endpointName] as DuplexChannelFactory
; } if (channelFactory == null) { channelFactory = new DuplexChannelFactory
(callbackObject, endpointName); //锁定通道工厂集合 lock (channelFactories.SyncRoot) { //更新当前通道终结点对象 channelFactories[endpointName] = channelFactory; } } return channelFactory; } }}
View Code

服务终结点配置类:EndpointNames

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace WCF.Client{       ///     /// 功    能:终结点名字    /// 创 建 人:龚安川    /// 创建时间:XXXX    ///     public static class EndpointNames    {        ///         /// 计算服务        ///         public const string CalculatorService = "CalculatorService";            ///         /// 双向通讯服务        ///         public const string DuplexMessageService = "DuplexMessageService";            }}
View Code

 

二、双通道CallBackHandle: WCF.Duplex

DuplexMessage客户端回调服务实现类: DuplexMessageCallBack

利用callback方法,将回掉通过注册的事件传递到外面

using System;using System.Collections.Generic;using System.Linq;using System.ServiceModel;using System.Text;using System.Threading;using System.Threading.Tasks;using WCF.Client;using WCF.Contract;namespace WCF.Duplex{    ///     /// 功    能:客户端回调服务实现类    /// 创 建 人:龚安川    /// 创建时间:    ///     public class DuplexMessageCallBack : IDuplexMessageCallBack    {        #region [变量定义]        ///         /// 唯一实例        ///         private static DuplexMessageCallBack _Instance;        ///         /// 客户端回调对象锁        ///         private static object lockObj = new object();        ///         /// 心跳线程        ///         private Thread HeadtThread = null;        ///         /// 订阅线程        ///         private Thread SubscribeThread = null;        ///         /// 是否心跳检测        ///         private bool isHearting = false;        ///         /// 是否订阅        ///         private bool isSubscribe = false;        #endregion        public DuplexMessageCallBack()        {        }        ///         /// 获取唯一实例        ///         /// 
public static DuplexMessageCallBack GetInstance() { lock (lockObj) { if (_Instance == null) _Instance = new DuplexMessageCallBack(); return _Instance; } } #region [委托和事件定义] /// /// 收到问号委托 /// /// public delegate void DelegateGreet(string messages); /// /// 收到离开委托 /// /// public delegate void DelegateLeave(string ip); /// /// 收到报警事件 /// public event DelegateGreet OnGreet; /// /// 恢复报警事件 /// public event DelegateLeave OnLeave; #endregion #region IDuplexMessageCallBack 成员 //服务端问好 public void Greet(string msg) { if (null != OnGreet) { OnGreet(msg); } } //服务端推送客户端离开 public void Leave(string ip) { if (null != OnLeave) { OnLeave(ip); } } #endregion #region [公开方法] /// /// 订阅报警 /// public void SubScribeAlarm() { /*如果第一次订阅失败,一直订阅直到成功为止*/ if (!isSubscribe) { ThreadStart sbuTs = new ThreadStart(Subscribing); SubscribeThread = new Thread(sbuTs); SubscribeThread.IsBackground = true; SubscribeThread.Start(); } if (!isHearting) { isHearting = true; ThreadStart ts = new ThreadStart(Hearting); HeadtThread = new Thread(ts); HeadtThread.IsBackground = true; HeadtThread.Start(); } } /// /// 取消报警订阅 /// public void UnSunScribeAlarm() { isHearting = false; if (HeadtThread != null) { HeadtThread.Abort(); } if (!isSubscribe) { if (SubscribeThread != null) { SubscribeThread.Abort(); } } else { try { InstanceContext context = new InstanceContext(this); WCFClient.Instance.GetService
(context).UnSbuscribeAlarm(); } catch { } isSubscribe = false; } } #endregion #region [私有方法] //订阅定时器事件 private void Subscribing() { InstanceContext context = new InstanceContext(this); while (!isSubscribe) { try { //客户端请求报警 WCFClient.Instance.GetService
(context).SubscribeAlarm(); isSubscribe = true; } catch (ThreadAbortException ex) { return; } catch { Thread.Sleep(5000); } } } //WCF客户端心跳线程 private void Hearting() { InstanceContext context = new InstanceContext(this); while (isHearting) { if (!isSubscribe) { Thread.Sleep(5000); continue; } try { //客户端发送线条-避免客户端下线 Thread.Sleep(5000); WCFClient.Instance.GetService
(context).Login(Guid.NewGuid().ToString()); } catch (ThreadAbortException ex) { return; } catch (Exception ex) { } } } #endregion }}
View Code

三、客户端演示程序。

 

 后台代码:

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.ServiceModel;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using WCF.Client;using WCF.Contract;using WCF.Duplex;namespace WcfClient{    public partial class Form1 : Form    {        public Form1()        {            InitializeComponent();            //不捕获线程错误调用            //CheckForIllegalCrossThreadCalls = false;        }        private void btnOne_Click(object sender, EventArgs e)        {            //仅用一个加法测试            var result = WCFClient.Instance.GetService
().Add(2, 3); listBox1.Items.Add("单向加运算结果为:" + result); } private void btnTwo_Click(object sender, EventArgs e) { //创建客户端回调服务对象 DuplexMessageCallBack callback = new DuplexMessageCallBack(); //创建通讯上下文 InstanceContext context = new InstanceContext(callback); //收到问号信号事件注册 callback.OnGreet += Form1_OnGreet; //收到离开信号事件注册 callback.OnLeave += Form1_OnLeave; //订阅报警 //DuplexMessageCallBack.GetInstance().SubScribeAlarm(); try { WCFClient.Instance.GetService
(context).Login("张三"); } catch (Exception ex) { MessageBox.Show("客户端调用双向服务登录异常!"); } //listBox1.Items.Add("单向加运算结果为:" + result); } //问号处理 void Form1_OnLeave(string ip) { listBox1.Items.Add("双向收到离开信号:" + ip); } //离开处理 void Form1_OnGreet(string messages) { listBox1.Items.Add("双向收到问号信号:" + messages); //建议安全的访问方式 listBox1.Invoke(new Action(() => listBox1.Items.Add("双向收到问号信号:" + messages))); } }}
View Code

演示结果如下:

 

转载于:https://www.cnblogs.com/82767136/articles/6439217.html

你可能感兴趣的文章
克罗谈投资策略03_你所期望的赌博方式
查看>>
克罗谈投资策略04_感觉与现实
查看>>
通向财务自由之路01_导读
查看>>
通向财务自由之路02_成功的决定因素:你
查看>>
中低频量化交易策略研发01_引言
查看>>
中低频量化交易策略研发06_推进的择时策略
查看>>
史丹·温斯坦称傲牛熊市的秘密
查看>>
期货市场技术分析01_理论基础
查看>>
期货市场技术分析02_趋势的基本概念
查看>>
期货市场技术分析03_主要反转形态
查看>>
期货市场技术分析04_持续形态
查看>>
期货市场技术分析05_交易量和持仓兴趣
查看>>
TB交易开拓者入门教程
查看>>
TB创建公式应用dll失败 请检查用户权限,终极解决方案
查看>>
python绘制k线图(蜡烛图)报错 No module named 'matplotlib.finance
查看>>
talib均线大全
查看>>
期货市场技术分析06_长期图表和商品指数
查看>>
期货市场技术分析07_摆动指数和相反意见理论
查看>>
满屏的指标?删了吧,手把手教你裸 K 交易!
查看>>
不吹不黑 | 聊聊为什么要用99%精度的数据回测
查看>>