一、模块结构

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

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下载最新版本

InChatter系统之客户端消息处理中心的更多相关文章

  1. InChatter系统之客户端实现原理与阶段小结

    InChatter客户端的开发可以说是目前系统的阶段性结尾了.很抱歉的是,这篇文章来的这么晚,迟到了这么久. 在客户端的开发主要针对两个方面: 消息的传输与处理 消息的UI交互处理 一.消息的传输与处 ...

  2. InChatter系统之服务器开发(二)

    现在我们继续进行InChatter系统的服务器端的开发,今天我们将实现服务契约同时完成宿主程序的开发,今天结束之后服务器端将可以正常运行起来. 系统的开发是随着博客一起的,颇有点现场直播的感觉,所有在 ...

  3. iOS系统及客户端软件测试的基础介绍

    iOS系统及客户端软件测试的基础介绍 iOS现在的最新版本iOS5是10月12号推出,当前版本是4.3.5 先是硬件部分,采用iOS系统的是iPad,iPhone,iTouch这三种设备,其中iPho ...

  4. 团队项目-北航MOOC系统Android客户端 NABC

    北航MOOC系统Android客户端 NABC (N) Need 需求 MOOC的全名是Massive Open Online Course,被称作大型开放式网络课程.2012年,美国的顶尖大学陆续设 ...

  5. InChatter系统之服务客户端的开发

    今天终于开始客户端的开发了,客户端完成以后,我们将可以进行简单的交流.开发完成的程序只是一个很简单的雏形,在本系统完成以后,以及完成的过程中,大家都可以下载源码,在此基础上融入自己的想法和尝试,可以按 ...

  6. InChatter系统之服务器开发(一)

    服务器端是整个消息系统的中枢,类似与人类的大脑.没有他,根本无法实现客户端之间的交流,为什么呢?这也涉及到我们的系统涉及,在服务器端,每个客户端的标识数据都会在服务器端进行保存,在这种情况下,当某一个 ...

  7. cas单点登录系统:客户端(client)详细配置

    最近一直在研究cas登录中心这一块的应用,分享一下记录的一些笔记和心得.后面会把cas-server端的配置和重构,另外还有这几天再搞nginx+cas的https反向代理配置,以及cas的证书相关的 ...

  8. 分布式高性能消息处理中心HPMessageCenter

    # HPMessageCenter 高性能消息分发中心.用户只需写好restful接口,在portal里面配置消息的处理地址,消息消费者就会自动访问相关接口,完成消息任务. ### 部署说明 **创建 ...

  9. cas单点登录系统:客户端(client)详细配置(包含统一单点注销配置)

    最近一直在研究cas登录中心这一块的应用,分享一下记录的一些笔记和心得.后面会把cas-server端的配置和重构,另外还有这几天再搞nginx+cas的https反向代理配置,以及cas的证书相关的 ...

随机推荐

  1. 初识 flask

    1,Python现阶段三大主流web框架Django, Tornado, Flask对比 Django主要特点是大而全,集成了很多组件,列如:Models Admin Form等等,不管用得用不着反正 ...

  2. Calling a parent window function from an iframe

    I want to call a parent window JavaScript function from an iframe. <script>function abc(){ ale ...

  3. Android Studio配置完毕Genymotion 看不到Genymotion图标

    没有打开toolBar想要看到genymotion插件图标,AndroidStudio单击视图(view)>工具栏显示工具栏(toolbar)

  4. RK3288以太网的mac地址调试笔记【学习笔记】【原创】

    平台信息:内核:linux3.1.0系统:android/android6.0平台:RK3288 作者:庄泽彬(欢迎转载,请注明作者) 邮箱:2760715357@qq.com 说明:提供以太网mac ...

  5. BZOJ_5343_[Ctsc2018]混合果汁_二分答案+主席树

    BZOJ_5343_[Ctsc2018]混合果汁_二分答案+主席树 题意:给出每个果汁的价格p,美味度d,最多能放的体积l.定义果汁混合后的美味度为果汁的美味度的最小值. m次询问,要求花费不大于g, ...

  6. win7上安装macaca的报错问题

    macaca网上的各种教程中,都建议使用淘宝源安装macaca,使用淘宝源就需要先安装cnpm,在win7上切换到淘宝源安装cnpm后(npm install -g cnpm --registry=h ...

  7. VC++6.0不兼容win10导致调试按钮不能正常作用得解决方案

    win10正式版是一个全新的操作系统,所以我们在系统中运行类似VC6这类旧软件时,难免会遇到一些问题. 比如,现在有些用户在win10环境下运行VC6时,按F10.F11进行单步调试, 会出现:Unh ...

  8. CF915E Physical Education Lessons(珂朵莉树)

    中文题面 据说正解是动态开点线段树而且标记也不难下传的样子 然而这种区间推平的题目还是喜欢写珂朵莉树啊……码量小…… 虽然真要构造的话随便卡…… //minamoto #include<cstd ...

  9. [App Store Connect帮助]七、在 App Store 上发行(1)App 发行流程概述

    在 App Store 上发行 App 的一般流程如下. 第 1 步:选择您的构建版本 每个 App 都可以有多个版本,且每个版本也可以有多个构建版本.若要在 App Store 上发行您的 App, ...

  10. 【CSS】少年,你想拥有写轮眼么?

    最近笔者在公司内部开展了一次CSS讲座,由于授课经验不太足,授课效果自我感觉并不太好,不过课中有一个笔者用CSS写的一个小效果,其中还是包含了蛮多CSS的常见知识点的,正好也有部分同学很感兴趣如何实现 ...