离上次发表文章已经挺久的了,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[]传输,大家也能想到,这里返回值也将使用序列化传输。
好吧,数据契约定义完成了,下面来看下我们定义的服务契约与回调契约吧。服务契约是客户端调用服务的接口。
服务契约:
[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
回调契约:回调契约是服务调用客户端的接口。
[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就是一个客户端与服务端连接与操作的桥梁,在这里可以进行任何想要的操作。
接下来来看下我们核心服务和核心客户端的实现。
核心服务:
[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 已销毁"); } } }
核心客户端:
[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
http://www.cnblogs.com/marksun/category/342642.html
这些文章看着都不错,我个人挺喜欢的。