(在阅读该文之前,请先阅读 ESFramework 4.0 概述 ,会对本文的理解更有帮助。)
ESFramework/ESPlatform 4.0 的终极目标是为百万级的用户同时在线提供支持,因为强大,所以使用也较为复杂,配置也较多。但是如果我们的应用只是一个中小型的通信应用(同时在线5000人以下),直接使用ESPlatform就有点显得杀鸡用牛刀了。ESPlus.Rapid提供了一种快速的方式,来解决类似中小型的通信应用,以最简洁的方式来使用ESFramework。
使用ESPlus.Rapid来构建你的ESFramework通信程序,你只需要了解两个引擎(服务端引擎和客户端引擎)和几个组件的接口就可以了,上手非常容易。废话不多说,先来看看这两个引擎的接口。
一.迅捷的通信引擎
首先是服务端引擎:
/// <summary>
/// 迅捷的服务端引擎。基于TCP、使用二进制协议。
/// </summary>
public interface IRapidServerEngine
{
/// <summary>
/// 通过此接口,可以获取用户的相关信息以及用户上/下线的事件通知。
/// </summary>
ICoreUserManager UserManager { get; }
/// <summary>
/// 通过此接口,服务端可以发送广播消息和将目标用户从服务器中踢出,并关闭其对应的tcp连接。
/// </summary>
IBasicController BasicController { get; set; }
/// <summary>
/// 通过此接口,服务端可以主动向在线用户发送/投递自定义信息。
/// </summary>
ICustomizeInfoController CustomizeInfoController { get; }
/// <summary>
/// 完成服务端引擎的初始化,并启动服务端引擎。
/// </summary>
/// <param name="port">用于提供tcp通信服务的端口</param>
/// <param name="customizeHandler">服务器通过此接口来处理客户端提交给服务端(且最终目的地是服务端)的非转发消息。</param>
void Initialize(int port, ICustomizeInfoBusinessHandler customizeHandler);
/// <summary>
/// 完成服务端引擎的初始化,并启动服务端引擎。
/// </summary>
/// <param name="port">用于提供tcp通信服务的端口</param>
/// <param name="customizeHandler">服务器通过此接口来处理客户端提交给服务端(且最终目的地是服务端)的非转发消息。</param>
/// <param name="friendsManager">服务器通过此接口来获取好友关系,如此,比如当某用户上下线时,服务器会自动发送通知给其相关好友。</param>
/// <param name="groupManager">服务器通过此接口来获取某个分组内的成员列表信息,如此,可以发送广播信息。</param>
void Initialize(int port, ICustomizeInfoBusinessHandler customizeHandler, IFriendsManager friendsManager,IGroupManager groupManager);
/// <summary>
/// ConfigMainServerForm 可以为服务端提供默认的主窗体,该窗体用于显示在线用户相关数据、连接数、线程数等信息。
/// </summary>
/// <param name="form">默认的主窗体</param>
void ConfigMainServerForm(MainServerForm form);
/// <summary>
/// Close 关闭服务端引擎。
/// </summary>
void Close();
}
我们可以调用Initialize方法启动服务端引擎,比如demo(后面会给出下载地址)中的代码是这样的:
//如果是其它类型的授权用户,请使用下面的语句设定正确的授权用户ID和密码。
ESFramework.AuthorizationVerifier.SetAuthorizedUser(AuthorizationVerifier.FreeUser, "");
ESPlus.Rapid.RapidServerEngine rapidServerEngine = new ESPlus.Rapid.RapidServerEngine();
rapidServerEngine.Initialize(9018, new EmptyCustomizeInfoBusinessHandler());
ESPlus.Widgets.MainServerForm mainForm = new ESPlus.Widgets.MainServerForm();
rapidServerEngine.ConfigMainServerForm(mainForm);
Application.Run(mainForm);
上述代码初始化了服务端引擎,并在9018 tcp端口进行监听。并且为该服务端引擎配置了一个默认的主窗体,用于显示用户在线状态,执行完Application.Run(mainForm);之后,会出现如下界面:
接下来看看客户端引擎:
/// <summary>
/// 迅捷的客户端引擎。基于TCP、使用二进制协议。
/// </summary>
public interface IRapidPassiveEngine
{
/// <summary>
/// 每隔多长时间(秒)发送一次心跳消息。如果小于等于0,表示不发送定时心跳。
/// </summary>
int HeartBeatSpanInSecs { get; set; }
/// <summary>
/// 通过该接口暴露的事件来了解tcp连接状态的变化,如连接断开、重连开始、重连成功等。
/// </summary>
ITcpPassiveEngine TcpPassiveEngine { get; }
/// <summary>
/// 该接口用于向服务器发送基本的请求,如获取自己的IP、获取所有在线用户列表等等
/// </summary>
IBasicOutter BasicOutter { get; }
/// <summary>
/// 该接口用于向服务器或其它在线用户发送自定义信息。
/// </summary>
ICustomizeInfoOutter CustomizeInfoOutter { get; }
/// <summary>
/// 完成客户端引擎的初始化,并与服务器建立TCP连接。
/// </summary>
/// <param name="userID">当前登录的用户ID,由数字和字母组成,最大长度为10</param>
/// <param name="serverIP">服务器的IP地址</param>
/// <param name="serverPort">服务器的端口</param>
/// <param name="basicHandler">基础处理器,用于处理服务器发出的与状态相关的通知</param>
/// <param name="customizeInfoBusinessHandler">自定义处理器,用于处理服务器或其它用户发送过来的消息</param>
void Initialize(string userID, string serverIP, int serverPort, IBasicBusinessHandler basicHandler, ICustomizeInfoBusinessHandler customizeHandler);
/// <summary>
/// 关闭客户端通信引擎。
/// </summary>
void Close();
}
我们再看demo中的客户端引擎如何完成初始化的:
RapidPassiveEngine rapidPassiveEngine = new RapidPassiveEngine();
MainForm mainForm = new MainForm();
rapidPassiveEngine.Initialize(loginForm.UserID, "127.0.0.1", 9018, mainForm, mainForm);
rapidPassiveEngine.Initialize方法将连接本地的9018端口,并且后面两个参数都传递了mainForm,表明mainForm即实现了IBasicBusinessHandler接口也实现了ICustomizeInfoBusinessHandler接口。
二.客户端:如何向服务端或其它在线用户发送消息
好了,客户端引擎已经初始化完成,现在可以开始通信了,比如,某个登录的客户端用户aa01如何将一个文本消息发送给在线用户aa02了?IRapidPassiveEngine接口暴露的CustomizeInfoOutter属性可以帮你完成这件事情:
rapidPassiveEngine.CustomizeInfoOutter.Send("aa02",0, System.Text.Encoding.UTF8.GetBytes("Hello!"));
以下是ESPlus.Application.CustomizeInfo.Passive.ICustomizeInfoOutter接口定义:
/// <summary>
/// 该接口用于向服务器或其它在线用户发送自定义信息、同步调用请求、或广播。
/// zhuweisky 2010.08.17
/// </summary>
public interface ICustomizeInfoOutter :IOutter
{
/// <summary>
/// 向服务器发送二进制信息。
/// </summary>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制信息</param>
void Send(int informationType, byte[] info);
/// <summary>
/// 向服务器提交请求信息,并返回服务器的应答信息。如果超时没有应答则将抛出Timeout异常。
/// </summary>
/// <param name="informationType">自定义请求信息的类型</param>
/// <param name="info">请求信息</param>
/// <returns>服务器的应答信息</returns>
byte[] CommitRequest(int informationType, byte[] info);
/// <summary>
/// 向在线目标用户提交请求信息,并返回应答信息。如果目标用户不在线,或超时没有应答则将抛出Timeout异常。
/// </summary>
/// <param name="targetUserID">接收并处理请求消息的目标用户ID</param>
/// <param name="informationType">自定义请求信息的类型</param>
/// <param name="info">请求信息</param>
/// <returns>应答信息</returns>
byte[] CommitP2PRequest(string targetUserID, int informationType, byte[] info);
/// <summary>
/// 向在线用户targetUserID发送二进制信息。如果目标用户不在线,则服务端会调用ICustomizeInfoBusinessHandler.OnTransmitFailed方法来通知应用程序。
/// </summary>
/// <param name="targetUserID">接收消息的目标用户ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制信息</param>
void Send(string targetUserID, int informationType, byte[] info);
/// <summary>
/// 向目标组内所有在线用户广播二进制信息。(服务端采用Post)
/// </summary>
/// <param name="groupID">接收广播信息的目标组的ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制信息</param>
void BroadcastInGroup(string groupID, int informationType, byte[] info);
}
该接口中定义了五种方法:向服务器发送信息、同步调用服务端、同步调用客户端、向其他的在线用户发送信息、向某个组内的成员广播信息。关于同步调用的更多内容可以参见ESFramework 4.0 进阶(07)-- 消息同步调用。
三.服务端:如何主动向客户端发送消息?
RapidServerEngine暴露的CustomizeInfoController属性可以在服务端主动向在线用户发送/投递自定义信息。
/// <summary>
/// 服务端主动向用户发送/投递自定义信息或广播以及同步调用客户端的控制接口。
/// </summary>
public interface ICustomizeInfoController
{
/// <summary>
/// 当收到来自客户端(由ICustomizeInfoOutter发出)的任何自定义信息时,将触发该事件。
/// </summary>
event CbGeneric<Information> InformationReceived;
/// <summary>
/// 向ID为userID的在线用户发送二进制信息。如果用户不在线,则直接返回。
/// </summary>
/// <param name="userID">接收消息的用户ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制信息</param>
void Send(string userID, int informationType, byte[] info);
/// <summary>
/// 向ID为userID的在线用户投递二进制信息。如果用户不在线,则直接返回。
/// </summary>
/// <param name="userID">接收消息的用户ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制信息</param>
void Post(string userID, int informationType, byte[] info);
/// <summary>
/// 询问在线客户端,并返回应答信息。如果目标用户不在线,或超时没有应答则将抛出Timeout异常。
/// </summary>
/// <param name="userID">接收并处理服务器询问的目标用户ID</param>
/// <param name="informationType">自定义请求信息的类型</param>
/// <param name="info">请求信息</param>
/// <returns>客户端给出的应答信息</returns>
byte[] QueryClient(string userID, int informationType, byte[] info);
/// <summary>
/// 向目标组内的在线用户发送二进制广播信息。
/// </summary>
/// <param name="groupID">接收消息的组ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制广播信息</param>
void SendBroacast(string groupID, int informationType, byte[] info);
/// <summary>
/// 向目标组内的在线用户投递二进制广播信息。
/// </summary>
/// <param name="groupID">接收消息的组ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制广播信息</param>
void PostBroacast(string groupID, int informationType, byte[] info);
}
(1)应用程序在服务端可以通过预定InformationReceived事件来监控所有来自客户端的自定义信息。注意,该事件处理函数不能抛出异常,否则将导致后续消息处理流程中断;另外,该事件处理函数应尽快返回。
(2)服务端也可以通过QueryClient同步调用客户端 -- 即服务端提交请求,由客户端处理完毕后,返回结果给服务端。ICustomizeInfoController.QueryClient方法刚好与ICustomizeInfoOutter.CommitRequest方法的流程相反。
(3)Send和Post的区别是,Send是同步发送的,Post是异步发送的。
四.客户端:接收到消息后如何处理它们?
客户端可以接收来自服务端的消息和来自其它客户端的消息。接着刚才的例子,在aa02那一方,客户端引擎会调用ICustomizeInfoBusinessHandler接口的HandleInformation方法来处理来自aa01的"Hello"文本信息。这也是为什么需要在rapidPassiveEngine.Initialize方法中传入ICustomizeInfoBusinessHandler引用的原因了。
ESPlus.Application.CustomizeInfo.Passive.ICustomizeInfoBusinessHandler接口定义如下:
/// <summary>
/// 客户端通过实现此接口来处理来自客户端或服务器的自定义信息。
/// </summary>
public interface ICustomizeInfoBusinessHandler
{
/// <summary>
/// 处理来自其他用户的二进制信息。
/// </summary>
/// <param name="sourceUserID">发出信息的用户ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制信息</param>
void HandleInformation(string sourceUserID, int informationType, byte[] info);
/// <summary>
/// 处理来自服务端的二进制信息。(即处理服务端ICustomizeInfoController.Send或Post发出的请求)
/// </summary>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制信息</param>
void HandleInformationFromServer(int informationType, byte[] info);
/// <summary>
/// 处理来自服务端的询问信息(同步调用请求),并给出应答信息。(即处理服务端ICustomizeInfoController.QueryClient发出的请求)
/// </summary>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制信息</param>
/// <returns>应答信息</returns>
byte[] HandleQueryFromServer(int informationType, byte[] info);
/// <summary>
/// 处理来自其他用户的二进制广播信息。
/// </summary>
/// <param name="broadcasterID">发出广播信息的用户ID</param>
/// <param name="groupID">接收广播信息的组ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制广播信息</param>
void HandleBroadcast(string broadcasterID, string groupID, int informationType, byte[] info);
/// <summary>
/// 处理来自服务器的二进制广播信息。
/// </summary>
/// <param name="groupID">接收广播信息的组ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制广播信息</param>
void HandleBroadcastFromServer(string groupID, int informationType, byte[] info);
/// <summary>
/// 处理来自其它在线用户的P2P同步调用请求并返回应答信息。(即处理客户端ICustomizeInfoOutter.CommitP2PRequest发出的请求)
/// </summary>
/// <param name="sourceUserID">发送请求信息的用户ID</param>
/// <param name="informationType">自定义请求信息的类型</param>
/// <param name="info">P2P请求信息</param>
/// <returns>P2P应答信息</returns>
byte[] HandleP2PRequest(string sourceUserID, int informationType, byte[] info);
}
五.服务端:如何处理来自客户端的消息?
服务端接收到的来自客户端的消息可以分为两类,一类是交由服务器中转的消息,如刚才例子中的aa01发给aa02的消息(如果P2P通道可用,这样的消息将可以不再经过服务器中转);另外一类是真正由服务器的业务逻辑处理的消息。关于第一类消息,ESPlus.Rapid框架内部已经自动进行了转发,但如果接收转发消息的目标用户不在线,服务端也会通知应用程序。至于这种情况和第二类消息的处理,服务端都是通过IRapidServerEngine.Initialize方法传入的ESPlus.Application.CustomizeInfo.Server.ICustomizeInfoBusinessHandler接口来完成的。
ESPlus.Application.CustomizeInfo.Server.ICustomizeInfoBusinessHandler接口定义如下:
/// <summary>
/// 服务端通过此接口来处理来自客户端的自定义信息。
/// </summary>
public interface ICustomizeInfoBusinessHandler : IBusinessHandler
{
/// <summary>
/// 当因为目标用户不在线而导致服务端转发自定义信息失败时,框架将调用此方法来通知应用程序。
/// </summary>
/// <param name="information">转发失败的信息</param>
void OnTransmitFailed(Information information);
/// <summary>
/// 处理来自客户端的自定义二进制信息。
/// </summary>
/// <param name="sourceUserID">发送该信息的用户ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">二进制信息</param>
void HandleInformation(string sourceUserID, int informationType, byte[] info);
/// <summary>
/// 处理来自客户端的请求并返回应答信息。(即处理客户端ICustomizeInfoOutter.CommitRequest发出的请求)
/// </summary>
/// <param name="sourceUserID">发送该请求信息的用户ID</param>
/// <param name="informationType">自定义请求信息的类型</param>
/// <param name="info">请求信息</param>
/// <returns>应答信息</returns>
byte[] HandleRequest(string sourceUserID, int informationType, byte[] info);
}
只要是P2P消息因为用接收端户不在线时,而导致转发失败就会触发OnTransmitFailed事件,而我们可以通过预定该事件来实现类似离线消息的机制。
六.厘清ESPlus.Application.CustomizeInfo空间下接口方法之间的关系
刚刚我们已经介绍完了ESPlus.Application.CustomizeInfo命名空间下的主要接口的作用,这些接口的方法之间有对应关系。比如,客户端由ICustomizeInfoOutter接口发出的CommitRequest调用将被服务端ICustomizeInfoBusinessHandler接口的HandleRequest方法来处理,下图我们通过箭头将这些调用与处理关联起来:
对照这个关系图,我们就能很清楚地知道发出的每个调用将被框架回调哪个接口的哪个方法来处理,从而避免出现匹配错误的情况。有个特点很容易发现:客户端ICustomizeInfoBusinessHandler接口的方法,只要方法名称以“FromServer”结尾的,都表示处理来自服务端的消息;而若不是以“FromServer”结尾的,则表示处理来自其他客户端的消息。
七.服务端:我要踢掉某个在线用户,该怎么办?
IRapidServerEngine暴露的BasicController属性可以让服务端的业务逻辑直接进行一些控制动作,比如踢人和在某个组内广播消息。
ESPlus.Application.Basic.Server.IBasicController接口定义如下:
/// <summary>
/// 直接在从服务端发出相关控制指令(如踢人等)。
/// </summary>
public interface IBasicController
{
/// <summary>
/// 将目标用户从服务器中踢出,并关闭对应的连接。
/// </summary>
void KickOut(string targetUserID);
/// <summary>
/// 将目标消息广播给(当前连接的Master服务器上的)所有在线用户。
/// </summary>
/// <param name="msg">要广播的消息</param>
void Broadcast(string msg);
}
八.客户端:我是以管理员身份登录的,我要踢人,怎么办?
IRapidPassiveEngine接口暴露IBasicOutter接口可以让我们在客户端主动获取一些信息或发出一些控制指令。
ESPlus.Application.CustomizeInfo.Passive.IBasicOutter接口定义如下:
public interface IBasicOutter :IOutter
{
/// <summary>
/// 获取自己的IPE。
/// </summary>
/// <returns>通常是经过NAT之后的IPE</returns>
IPEndPoint GetMyIPE();
/// <summary>
/// 获取(当前连接的Master服务器上的)所有在线的用户列表。
/// </summary>
List<string> GetAllOnlineUsers();
/// <summary>
/// 查询用户是否在线。
/// </summary>
bool IsUserOnline(string userID);
/// <summary>
/// 登出。服务端接收到此消息后,可以立即关闭对应的连接(如果是基于TCP)以释放资源。
/// </summary>
void Logout();
/// <summary>
/// 命令(当前连接的Master)服务端将目标用户踢出。如果目标用户不在线或者不在当前连接的Master服务器上,则直接返回。
/// </summary>
/// <param name="targetUserID">要踢出的用户ID</param>
void KickOut(string targetUserID);
/// <summary>
/// 将目标消息广播给(当前连接的Master服务器上的)所有在线用户。(服务端采用Post)
/// </summary>
/// <param name="msg">要广播的消息</param>
void Broadcast(string msg);
/// <summary>
/// 向服务器发送心跳消息。被框架ESPlus.Application.Basic.Passive.HeartBeater使用。
/// </summary>
void SendHeartBeatMessage() ;
}
注意,IBasicOutter也提供了广播消息的Broadcast方法,不过这个Broadcast方法是向所有的在线用户广播信息,而ICustomizeInfoOutter的BroadcastInGroup方法是对某个组内的所有成员进行广播,两者是有区别的。
九.客户端:我如何得知好友上线/下线消息?
IRapidPassiveEngine在初始化Initialize方法中,传入的IBasicBusinessHandler接口用来处理来自服务器的广播消息之外,还处理来自服务端的众多通知,比如,好友上下线、自己超时掉线等等。
ESPlus.Application.CustomizeInfo.Passive.IBasicBusinessHandler接口:
/// <summary>
/// 客户端必须实现此接口,对服务端给出的相关通知作出正确的反映。
/// </summary>
public interface IBasicBusinessHandler : IBusinessHandler
{
/// <summary>
/// OnFriendConnected 好友上线。 服务端通过IFriendsManager发现好友。
/// </summary>
void OnFriendConnected(string friendID);
/// <summary>
/// OnFriendOffline 好友掉线。 服务端通过IFriendsManager发现好友。
/// </summary>
void OnFriendOffline(string friendID);
/// <summary>
/// OnBeingPushedOut 被同名用户挤掉线。此时,客户端引擎已被Dispose。
/// 发生于RelogonMode.ReplaceOld。
/// </summary>
void OnBeingPushedOut();
/// <summary>
/// OnTimeoutOffline 心跳超时掉线。此时,客户端引擎已被Dispose。
/// </summary>
void OnTimeoutOffline();
/// <summary>
/// OnHaveLogonNotify 当同名的用户已经登录,而且当前连接被忽略(已被服务端关闭)时调用此方法。此时,客户端引擎已被Dispose。
/// 发生于RelogonMode.IgnoreNew。
/// </summary>
void OnHaveLogonNotify();
/// <summary>
/// OnBeingKickedOut 被服务端踢出掉线。此时,客户端引擎已被Dispose。
/// </summary>
void OnBeingKickedOut();
/// <summary>
/// 处理来自其他用户的广播信息。
/// </summary>
/// <param name="broadcasterID">发出广播的用户ID</param>
/// <param name="msg">广播信息</param>
void HandleBroadcast(string broadcasterID, string msg);
/// <summary>
/// 处理来自服务器的广播信息。
/// </summary>
/// <param name="msg">广播信息</param>
void HandleBroadcastFromServer(string msg);
}
十.客户端:如何知道自己已经掉线?
IRapidPassiveEngine暴露了TcpPassiveEngine属性,ITcpPassiveEngine是RapidPassiveEngine内部使用的真正的核心引擎,通过ITcpPassiveEngine发布的事件,我们可以得知自己掉线/重连开始/重连成功(失败)等相关通知。ITcpPassiveEngine接口一些重要的事件和属性的定义摘抄如下:
/// <summary>
/// 当客户端与服务器的TCP连接断开时,将触发此事件。
/// </summary>
event CbGeneric ConnectionInterrupted;
/// <summary>
/// 自动重连开始时,触发此事件。
/// </summary>
event CbGeneric ConnectionRebuildStart;
/// <summary>
/// 自动重连成功后,触发此事件。
/// </summary>
event CbGeneric ConnectionRebuildSucceed;
/// <summary>
/// 自动重连超过最大重试次数时,表明重连失败,将触发此事件。
/// </summary>
event CbGeneric ConnectionRebuildFailure;
/// <summary>
/// 当前是否处于连接状态。
/// </summary>
bool Connected { get; }
/// <summary>
/// 当与服务器断开连接时,是否自动重连。
/// </summary>
bool AutoReconnect { get; set; }
关于ITcpPassiveEngine接口的更多信息,可以参见ESFramework4.0.chm帮助文档。
十一.服务端:如何得到在线用户的相关信息?
IRapidServerEngine暴露的UserManager属性可以让我们获取在线用户的一些基本信息。
ICoreUserManager接口定义如下:
public interface ICoreUserManager
{
/// <summary>
/// 获取目标在线用户的基础信息。
/// </summary>
/// <param name="userID">目标用户的ID</param>
/// <returns>如果目标用户不在线,则返回null</returns>
UserData GetUserData(string userID);
/// <summary>
/// 获取所有在线用户的ID列表。
/// </summary>
List<string> GetOnlineUserList();
/// <summary>
/// 如果是基于tcp引擎,则当tcp连接上接收或发送数据抛出异常时,将关闭连接,并触发此事件。
/// </summary>
event CbGeneric<UserData> SomeOneDisconnected;
/// <summary>
/// 如果是基于tcp引擎,当接收到新连接上的第一个消息时,将触发此事件。
/// </summary>
event CbGeneric<UserData> SomeOneConnected;
}
ICoreUserManager暴露了够用的与在线用户相关信息,如果想获取更多与用户管理相关的功能,可以将ICoreUserManager向上强转为IUserManager接口,关于IUserManager更多信息,可以参考ESFramework4.0.chm帮助文档。
到这里,你也许已经发现了一个小秘密,这也是ESPlus整个框架内部遵守的规则:凡是以"Outter"结尾的接口/组件(如IBasicOutter和ICustomizeInfoOutter接口),都是框架已经实现的,并暴露出来给你在客户端直接使用的;凡是以"Controller"结尾的接口/组件(如IBasicController接口),也是框架已经实现的,并暴露出来给你在服务端进行控制调用的;凡是以"Handler"结尾的(如IBasicBusinessHandler和ICustomizeInfoBusinessHandler接口),无论是服务端的还是客户端的,框架都没有提供"有意义的"实现的(那些以Empty开头的Handler相当于是占位符,它们实现了Handler接口,但本身不做任事情。NullObject模式,呵呵),你需要实现这些接口,并挂接到框架上(比如通过引擎的Initialize方法)以注入你的业务处理逻辑(IOC模式的运用),这样,当对应的消息来临时,框架会自动调用Handler的对应的方法。
通常,对于使用ESPlus.Rapid来进行ESFramework快速开发来说,上述的介绍已经够用了,如果想了解更多的信息和使用ESFramework/ESPlus/ESPlatform的高级特性和更强大的功能,可能需要一段时间的专业培训才可以。
最后,demo源码和相关文档可以到ESFramework 4.0 概述文末下载。
2011.03.08:ESFramework 4.0 快速上手 -- Rapid引擎(续)
关于《ESFramework 4.0快速上手》系列的更多文章,请参见 http://www.cnblogs.com/zhuweisky/category/261300.html
任何问题,请联系sky.zhuwei@163.com 或 QQ:372841921。that‘s all,thanks.
ESFramework 4.0 快速上手(01) -- Rapid引擎
原文:http://www.cnblogs.com/sylone/p/6096798.html