InChatter系统之客户端消息处理中心

一、模块结构

首先来看下客户端消息处理中心模块的简单结构:

ChatCallback:服务器端我们定义的回调接口IChatCallback的客户端实现

ChatMsgCenter:服务端的消息处理中心,所有的消息都将在这里进行分发处理,可以比作人的大脑中枢

ClientContext:登录信息描述,也可以理解为客户端唯一标识

DataHelper:数据库操作类,这里我们使用NDatabase的开源对象数据库,使用方法参考关法文档

Messager:消息类封装,在消息的基础上,添加了ID属性和IsRead属性

二、技术实现

1.ChatCallbck的实现原理

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InChatter.Client.Service
{
    public class ChatCallback:ChatServer.IChatCallback
    {
        public event Action<ChatServer.InChatterMessage> OnMessgeReceived;

        public void ReceiveMsg(ChatServer.InChatterMessage message)
        {
            if (OnMessgeReceived != null)
            {
                OnMessgeReceived(message);
            }
        }
    }
}

在ChatcallBack类中,我们添加了OnMessageReceived事件处理,由于回调的触发在服务器端,所以当服务器端调用ReceiveMsg方法时,我们为ChatCallback注册的事件,便可以执行并捕获对应的数据。

2.Messager消息类的封装

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InChatter.Client.Service
{
    public class Messager
    {
        public string Id { set; get; }
        public bool IsRead { set; get; }
        public ChatServer.InChatterMessage Message { set; get; }
        public Messager()
        {
            Id = Guid.NewGuid().ToString();
        }
    }
}

正如我前面解释的那样,这里对InChatterMessage进行了封装,添加了Id以便于我们进行相应的数据库等操作,而IsRead标识了消息的阅读状态

3.DataHelper类的实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InChatter.Client.Service
{
    public class DataHelper
    {
        #region Save
        public static bool Save(Messager message)
        {
            try
            {
                lock (string.Intern(ChatMsgCenter.Instance.DbUrl))
                {
                    using (var db = NDatabase.OdbFactory.Open(ChatMsgCenter.Instance.DbUrl))
                    {
                        db.Store(message);
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static bool Save(IEnumerable<Messager> msgList)
        {
            try
            {
                lock (string.Intern(ChatMsgCenter.Instance.DbUrl))
                {
                    using (var db = NDatabase.OdbFactory.Open(ChatMsgCenter.Instance.DbUrl))
                    {
                        foreach (var msg in msgList)
                        {
                            db.Store(msg);
                        }
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion

        public static bool Update(Messager message)
        {
            try
            {
                lock (string.Intern(ChatMsgCenter.Instance.DbUrl))
                {
                    using (var db = NDatabase.OdbFactory.Open(ChatMsgCenter.Instance.DbUrl))
                    {
                        var msg = (from item in db.AsQueryable<Messager>()
                                   where item.Id == message.Id
                                   select item).Single();
                        msg.IsRead = message.IsRead;
                        msg.Message = message.Message;
                        db.Store(msg);
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static bool Delete(string msgId)
        {
            try
            {
                lock (string.Intern(ChatMsgCenter.Instance.DbUrl))
                {
                    using (var db = NDatabase.OdbFactory.Open(ChatMsgCenter.Instance.DbUrl))
                    {
                        var msg = (from item in db.AsQueryable<Messager>()
                                   where item.Id == msgId
                                   select item).Single();
                        db.Delete(msg);
                    }
                }
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}

这里我们使用的NDatabase的开源对象数据库,这里有一个需要注意的地方是NDatabase没有明确的update方法,它使用的是读取并更新的方式,即从数据库中读取的数据,而后直接进行的操作并调用Store方法,将处理为更新(操作代码在同一个区域块内),这里需要特别注意,否则将会存储很多相同的实例,而无法应用更新。

4.ClientContext类的实现原理

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InChatter.Client.Service
{
    public class ClientContext
    {
        static Lazy<ClientContext> _Instance = new Lazy<ClientContext>();
        public static ClientContext Instance
        {
            get
            {
                return _Instance.Value;
            }
        }
        public string LoginId { set; get; }
        public string LoginName { set; get; }
    }
}

这里目前通过LoginId和LoginName标识登录状态,而Login将被用来标识客户端Id

5.ChatMsgCenter消息处理中心类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InChatter.Client.Service
{
    public class ChatMsgCenter
    {
        private static Lazy<ChatMsgCenter> _Instance = new Lazy<ChatMsgCenter>();

        public static ChatMsgCenter Instance
        {
            get
            {
                return _Instance.Value;
            }
        }

        public string DbUrl { set; get; }

        public ChatServer.ChatClient Client { set; get; }

        private ChatCallback callback { set; get; }

        public event Action<ChatServer.InChatterMessage> OnMessageReceived;

        public event Action<Messager> OnUnReadMessageRead;

        private ChatMsgCenter()
        {
            callback = new ChatCallback();
            Client = new ChatServer.ChatClient(new System.ServiceModel.InstanceContext(callback), "NetTcpBinding_IChat");
            callback.OnMessgeReceived+=callback_OnMessgeReceived;
        }

        private void callback_OnMessgeReceived(ChatServer.InChatterMessage message)
        {
            Messager msg = new Messager()
            {
                IsRead = false,
                Message = message,
            };
            DataHelper.Save(msg);
            if (OnMessageReceived != null)
            {
                OnMessageReceived(message);
            }
        }

        public void Login(string clientId)
        {
            Client.Login(clientId);
            DbUrl = "Messages\\"+clientId+".db";
        }

        public void SendMsg(ChatServer.InChatterMessage message)
        {
            Messager msg = new Messager()
            {
                IsRead = true,
                Message = message,
            };
            DataHelper.Save(msg);
            Client.SendMsg(msg.Message);
        }

        public void Logout(string clientId)
        {
            Client.Logout(clientId);
        }
    }
}

这里是使用单件来实现的系统类,并且还应用了延迟加载类的辅助LazyLoad,LazyLoad类的具体用法参考这里

在Login时,我们向服务器发送Login请求,并设置当前登录ClientContext的信息,同时设置数据存储地址,客户端将根据登录人ID来标识,每个人的存储都对应到自己Id地址的数据库中。

 

以上是整个客户端系统的重要部分,欢迎大家讨论,并提供宝贵意见

源码提供给大家:下载源码到CodePlex下载最新版本

posted @ 2013-11-11 22:51  Skysper  阅读(1115)  评论(4编辑  收藏  举报