zoukankan      html  css  js  c++  java
  • 客户端服务端通信的实现3

    一步步实现自己的框架系列(三):客户端服务端通信的实现

    离上次发表文章已经挺久的了,wcf这块确实挺烦人的,虽然用过几次,但是手写起来还是有点陌生,看了不少wcf的文章,终少有领悟,这里我捎带提起,更详细的我会推荐几篇不错文章供大家参考。

      首先看下wcf大概包括些什么内容,这里是让大家有个清晰的纲领,不会深入介绍wcf,再说这一块也不是我这个凡人能给大家三言两语就能说明白的。

      要使用wcf通信,首先要定义契约,我们再来看下wcf有哪些契约。

      wcf的四种契约,我给他按使用的优先级拍个序吧,Service Contract是必不可少的也是必须的,Data Contract 也是常会用到的,用来定义通信结构体,但是没有这个,我们使用基础类型也是能完成通信,其次是Fualt Contract通信失败的契约,这个能告诉我们调用失败的详细信息也是很重要的,最后是Message Contract,这个是最不常用的了,本文也不会用到,有兴趣的可以自己找点资料看看。

      好吧,引出我们今天的话题,客户端服务端通信的实现,关于通信设计模型大家可以看我第一篇的介绍,这里就不重复了。不管是客户端调用服务端还是服务端回调客户端,都是方法的调用,无非就是:(请求-回复)或者(请求),既然这样看下我定义的数据契约吧,定义的数据契约包括 请求数据契约 和 响应契约 两种。

    复制代码
        [DataContract(Namespace = "http://www.cnblogs.com/guanglin/", Name = "Request")]
        public class Request
        {
            [DataMember]
            public string InstanceId { get; set; }
    
            [DataMember]
            public string MethodName { get; set; }
    
            [DataMember]
            public string[] ParamTypes { get; set; }
    
            [DataMember]
            public byte[] Parameters { get; set; }
    
        }
    复制代码

      这个是请求契约其中MethodName为请求调用的方法名称,ParamType为请求调用的参数类型,Parameters为请求调用的参数,这里Parameters为什么使用byte[]数据类型呢?因为我们调用的方法参数的类型是不确定的,这里将参数序列化后传输,使用时再反序列化回来即可。这里还有个InstanceId是干什么用的呢,这跟我们的设计有关,我的客户端与服务端是基于页面创建的,这个InstanceId代表的是请求的页面服务或回调页面的唯一标识。

      接下来看下响应契约,这个就简单了。

    复制代码
        [DataContract(Namespace = "http://www.cnblogs.com/guanglin/", Name = "Response")]
        public class Response
        {
            [DataMember]
            public string InstanceId { get; set; }
    
            [DataMember]
            public byte[] Value { get; set; }
        }
    复制代码

      回复契约只有唯一标识和返回值,并且返回值也使用byte[]传输,大家也能想到,这里返回值也将使用序列化传输。

      好吧,数据契约定义完成了,下面来看下我们定义的服务契约与回调契约吧。服务契约是客户端调用服务的接口。

    服务契约:

     View Code
     [ServiceContract(CallbackContract=typeof(ICoreCallbackService),
            SessionMode = SessionMode.Required,
            Namespace="GL")]
        public interface ICoreService
        {
            #region 连接操作
            /// <summary>
            /// 连接到服务器,创建Session
            /// </summary>
            /// <param name="clientSessionInfo">客户端连接信息</param>
            /// <returns>连接的SessionId</returns>
            [OperationContract]
            [FaultContract(typeof(GLFaultContract))]
            string Connect(ClientConnectionInfo clientSessionInfo);
    
            /// <summary>
            /// 重新连接到服务器
            /// </summary>
            /// <param name="sessionId">重新连接的SessionId</param>
            [OperationContract]
            [FaultContract(typeof(GLFaultContract))]
            void Reconnect(string sessionId);
    
            /// <summary>
            /// 断开与服务器
            /// </summary>
            [OperationContract(IsTerminating = true)]
            [FaultContract(typeof(GLFaultContract))]
            void Disconnect();
            #endregion
    
            #region 页面操作
            /// <summary>
            /// 创建PageService实例返回实例id
            /// </summary>
            /// <param name="serviceTypeName">serviceTypeName</param>
            /// <returns>instanceId</returns>
            [OperationContract(IsOneWay = false)]
            [FaultContract(typeof(GLFaultContract))]
            string CreatePageService(string serviceTypeName);
    
            /// <summary>
            /// 销毁PageService实例
            /// </summary>
            /// <param name="instanceId">instanceId</param>
            [OperationContract(IsOneWay = true)]
            void DestoryPageService(string instanceId);
    
            /// <summary>
            /// 调用一个页面服务方法
            /// </summary>
            /// <param name="request">页面调用请求</param>
            /// <returns>页面调用回复</returns>
            [OperationContract]
            [FaultContract(typeof(GLFaultContract))]
            Response CallPageService(Request request);
    
            /// <summary>
            /// 单向调用一个页面服务方法
            /// </summary>
            /// <param name="request">页面调用请求</param>
            [OperationContract(IsOneWay = true)]
            void OneWayCallPageService(Request request);
    
            /// <summary>
            /// 调用Session公共服务
            /// </summary>
            /// <param name="request">服务请求参数</param>
            /// <returns>服务请求回复</returns>
            [OperationContract]
            [FaultContract(typeof(GLFaultContract))]
            Response CallService(Request request);
    
            /// <summary>
            /// 单向调用Session公共服务
            /// </summary>
            /// <param name="request">服务请求参数</param>
            [OperationContract(IsOneWay = true)]
            void OneWayCallService(Request request);
            #endregion

    回调契约:回调契约是服务调用客户端的接口。

     View Code
    [ServiceContract]
        public interface ICoreCallbackService
        {
            /// <summary>
            /// 页面回调
            /// </summary>
            /// <param name="request">页面调用参数</param>
            /// <returns>页面调用回复</returns>
            [OperationContract]
            [FaultContract(typeof(GLFaultContract))]
            Response PageCallback(Request request);
    
            /// <summary>
            /// 单向页面回调
            /// </summary>
            /// <param name="request">页面调用参数</param>
            [OperationContract(IsOneWay = true)]
            void OneWayPageCallback(Request request);
    
            /// <summary>
            /// 客户端回调
            /// </summary>
            /// <param name="request">客户端回调参数</param>
            /// <returns>客户端回调回复</returns>
            [OperationContract]
            [FaultContract(typeof(GLFaultContract))]
            Response ClientCallback(Request request);
    
            /// <summary>
            /// 单向客户端回调
            /// </summary>
            /// <param name="request">客户端回调参数</param>
            [OperationContract(IsOneWay = true)]
            void OneWayClientCallback(Request request);
        }

     契约定义完成,接下来看下Session的定义

    复制代码
        public interface ISession: IPartAccess
        {
            string SessionID { get; }
    
            ClientConnectionInfo ClientConnectionInfo { get; }
    
            TimeSpan TimeOut { get; }
    
            ICoreCallbackService CallbackService { get; }
    
            IContextChannel ConnectionChannel { get; }
    
            IPageServiceManager PageServiceManager { get; }
    
            bool IsDisposed { get; }
    
            void ReConnect(IContextChannel ConnectionChannel, ICoreCallbackService Callback);
    
            #region PageService 操作
    
            string CreatePageService(string serviceTypeName);
    
            void DestoryPageService(string instanceId);
    
            Response CallPageService(Request request);
    
            void OneWayCallPageService(Request request);
    
            Response CallService(Request request);
    
            void OneWayCallService(Request request);
    
            #endregion
        }
    复制代码
    复制代码
    public interface IPartAccess
        {
    
            /// <summary>
            /// 获取单实例插件
            /// </summary>
            /// <param name="partType"></param>
            /// <returns></returns>
            object GetSinglePart(Type partType);
    
            T GetSinglePart<T>();
    
            /// <summary>
            /// 获取多实例插件
            /// </summary>
            /// <param name="partType"></param>
            /// <returns></returns>
            IEnumerable<object> GetMultipleParts(Type partType);
    
            IEnumerable<T> GetMultipleParts<T>();
    
            /// <summary>
            /// 获取插件信息
            /// </summary>
            /// <param name="partType"></param>
            /// <returns></returns>
            IPartInformation GetPartInformation(object instance);
    
            /// <summary>
            /// 获取指定类型插件是否启用
            /// </summary>
            /// <param name="partType"></param>
            /// <returns></returns>
            bool IsPartEnabled(Type partType);
        }
    复制代码


       Session里定义了很多操作, 这里不仅有调用客户端的回调通道,还有操作Session级别的插件的访问,也有操作页面服务的访问接口,Session就是一个客户端与服务端连接与操作的桥梁,在这里可以进行任何想要的操作。

      接下来来看下我们核心服务和核心客户端的实现。

     核心服务:

     View Code
      [ServiceBehavior(
        ConcurrencyMode = ConcurrencyMode.Multiple,
        InstanceContextMode = InstanceContextMode.PerSession,
        UseSynchronizationContext = false,
        AddressFilterMode = AddressFilterMode.Any)]
        public class CoreService : ICoreService
        {
            public ISession Session { get; private set; }
    
            public ISessionManager SessionManager { get; private set; }
    
            public CoreService() { }
    
            public string Connect(ClientConnectionInfo clientSessionInfo)
            {
                //新连接创建Session
                var connectionChannel = OperationContext.Current.Channel;
                var callbackChannel = OperationContext.Current.GetCallbackChannel<ICoreCallbackService>();
                Session = new Session(clientSessionInfo, connectionChannel, callbackChannel);
                SessionManager = PartPlatform.Instance.GetSinglePart<ISessionManager>();
                SessionManager.RegistSession(Session);
                return Session.SessionID;
            }
    
            public void Reconnect(string sessionId)
            {
                var connectionChannel = OperationContext.Current.Channel;
                var callbackChannel = OperationContext.Current.GetCallbackChannel<ICoreCallbackService>();
                Session.ReConnect(connectionChannel, callbackChannel);
            }
    
            public void Disconnect()
            {
                VerifySession();
                SessionManager.UnRegistSession(Session.SessionID);
            }
    
            public string CreatePageService(string serviceTypeName)
            {
                VerifySession();
                return Session.CreatePageService(serviceTypeName);
            }
    
            public void DestoryPageService(string instanceId)
            {
                VerifySession();
                Session.DestoryPageService(instanceId);
            }
    
            public Response CallPageService(Request request)
            {
                VerifySession();
                return Session.CallPageService(request);
            }
    
            public void OneWayCallPageService(Request request)
            {
                VerifySession();
                Session.OneWayCallPageService(request);
            }
    
            public Response CallService(Request request)
            {
                VerifySession();
                return Session.CallService(request);
            }
    
            public void OneWayCallService(Request request)
            {
                VerifySession();
                Session.OneWayCallService(request);
            }
    
            private void VerifySession()
            {
                if (Session == null)
                {
                    throw new FaultException("Session 未创建");
                }
    
                if (Session.IsDisposed)
                {
                    throw new FaultException("Session 已销毁");
                }
            }
        }

    核心客户端:

     View Code
    [SinglePart]
        [PalatformPart]
        [PartMetadataAttribute("PartName", "CoreClient")]
        [PartMetadataAttribute("PartType", typeof(CoreClient))]
        [PartMetadataAttribute("PartDependencies", new Type[] { typeof(IPageManager) })]
        [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
        public class CoreClient : ICoreClient, ICoreServiceCallback
        {
            ILog _logger = LogManager.GetLogger(typeof(CoreClient));
    
            private IPageManager _pageManager = null;
    
            private CoreServiceClient _CoreServiceClient = null;
    
            public CoreClient()
            {
    
            }
    
            [PartActivationMethod]
            public void Initialize()
            {
    
            }
    
            private void InitalizeConnection()
            {
                if (_pageManager == null)
                {
                    _pageManager = PartPlatform.Instance.GetSinglePart<IPageManager>();
                }
                _CoreServiceClient = new CoreServiceClient(new InstanceContext(this));
            }
    
    
            #region ICoreClient
    
            public string SessionId { get; private set; }
    
            public string Connect(ClientConnectionInfo sessionInfo)
            {
                InitalizeConnection();
                var sessionId = this.TryCallServer(() => { return _CoreServiceClient.Connect(sessionInfo); }, "Connect");
    
                _logger.InfoFormat("connect to server done, SessionId:{0}", sessionId);
                return sessionId;
            }
    
            private static object _lockObj = new object();
    
            public bool Reconnect()
            {
                lock (_lockObj)
                {
                    if (this._CoreServiceClient.State == CommunicationState.Created)
                        return true;
    
                    //_CoreServiceClient.Close;
                    InitalizeConnection();
                    this.TryCallServer(() => { _CoreServiceClient.Reconnect(this.SessionId); }, "Reconnect");
    
                    return true;
                }
            }
    
            public void Disconnect()
            {
                VerifyConnection();
                this.TryCallServer(() => { _CoreServiceClient.Disconnect(); }, "Disconnect");
            }
    
            public string CreatePageService(string serviceTypeName)
            {
                VerifyConnection();
                return this.TryCallServer(() => { return _CoreServiceClient.CreatePageService(serviceTypeName); }, "CreatePageService", serviceTypeName);
            }
    
            public void DestoryPageService(string instanceId)
            {
                VerifyConnection();
                this.TryCallServer(() => { _CoreServiceClient.DestoryPageService(instanceId); }, "DestoryPageService", instanceId);
            }
    
            public Response CallPageService(Request request)
            {
                VerifyConnection();
                return this.TryCallServer(() => { return _CoreServiceClient.CallPageService(request); }, "CallPageService");
            }
    
            public void OneWayCallPageService(Request request)
            {
                VerifyConnection();
                this.TryCallServer(() => { _CoreServiceClient.OneWayCallPageService(request); }, "OneWayCallPageService");
            }
    
            public Response CallService(Request request)
            {
                VerifyConnection();
                return this.TryCallServer(() => { return _CoreServiceClient.CallService(request); }, "CallService");
            }
    
            public void OneWayCallService(Request request)
            {
                VerifyConnection();
                this.TryCallServer(() => { _CoreServiceClient.OneWayCallService(request); }, "OneWayCallService");
            }
    
            public void VerifyConnection()
            {
    
                if (_CoreServiceClient.State == CommunicationState.Faulted ||
                    _CoreServiceClient.State == CommunicationState.Closing ||
                    _CoreServiceClient.State == CommunicationState.Closed)
                {
                    Reconnect();
                }
            }
            #region TryCallServer
    
            private void TryCallServer(Action task, string methodName, params string[] args)
            {
                DoTryCallServer(task, methodName, args);
            }
    
            private T TryCallServer<T>(Func<T> task, string methodName, params string[] args)
            {
                return (T)DoTryCallServer(task, methodName, args);
            }
    
            private object DoTryCallServer(Delegate method, string methodName, params string[] args)
            {
                try
                {
                    _logger.DebugFormat("Start to Invoke {0},Args:{1}", methodName, string.Join(",", args));
                    var result = method.DynamicInvoke();
                    _logger.DebugFormat("Invoke {0} done.", methodName);
                    return result;
                }
                catch (TargetInvocationException e)
                {
                    //TODO:Callservice异常处理
                    throw e;
                }
            }
    
            #endregion
    
            #endregion ICoreClient
    
    
    
    
            #region ICoreServiceCallback
    
            public Response PageCallback(Request request)
            {
                var page = _pageManager.GetPage(request.InstanceId);
                var invokeResult = page.ReflectCallInstanceMethod(request.MethodName, request.ParamTypes, request.Parameters.DeserializeToObject<object[]>());
                var response = new Response();
                response.InstanceId = request.InstanceId;
                response.Value = invokeResult.SerializeToByteArray();
                return response;
            }
    
            public void OneWayPageCallback(Request request)
            {
                var page = _pageManager.GetPage(request.InstanceId);
                page.ReflectCallInstanceMethod(request.MethodName, request.ParamTypes, request.Parameters.DeserializeToObject<object[]>());
            }
    
            public Response ClientCallback(Request request)
            {
                throw new NotImplementedException();
            }
    
            public void OneWayClientCallback(Request request)
            {
                throw new NotImplementedException();
            }
    
            #endregion ICoreServiceCallback
        }

    这样我们的客户端服务端核心通信就实现了,下一篇将介绍页面与页面服务。

    推荐wcf的参考文章:

     

    DanielWise 的wcf系列文章

    http://www.cnblogs.com/danielWise/archive/2011/06/23/2087937.html

    MarkSun 的wcf文章

    http://www.cnblogs.com/marksun/category/342642.html

    这些文章看着都不错,我个人挺喜欢的。

     
     
    分类: C#
  • 相关阅读:
    prototype.js超强的javascript类库
    MySQL Server Architecture
    Know more about RBA redo block address
    MySQL无处不在
    利用Oracle Enterprise Manager Cloud Control 12c创建DataGuard Standby
    LAMP Stack
    9i中DG remote archive可能导致Primary Database挂起
    Oracle数据库升级与补丁
    Oracle为何会发生归档日志archivelog大小远小于联机重做日志online redo log size的情况?
    Oracle Ksplice如何工作?How does Ksplice work?
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3139268.html
Copyright © 2011-2022 走看看