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下载最新版本)
InChatter系统之客户端消息处理中心的更多相关文章
- InChatter系统之客户端实现原理与阶段小结
InChatter客户端的开发可以说是目前系统的阶段性结尾了.很抱歉的是,这篇文章来的这么晚,迟到了这么久. 在客户端的开发主要针对两个方面: 消息的传输与处理 消息的UI交互处理 一.消息的传输与处 ...
- InChatter系统之服务器开发(二)
现在我们继续进行InChatter系统的服务器端的开发,今天我们将实现服务契约同时完成宿主程序的开发,今天结束之后服务器端将可以正常运行起来. 系统的开发是随着博客一起的,颇有点现场直播的感觉,所有在 ...
- iOS系统及客户端软件测试的基础介绍
iOS系统及客户端软件测试的基础介绍 iOS现在的最新版本iOS5是10月12号推出,当前版本是4.3.5 先是硬件部分,采用iOS系统的是iPad,iPhone,iTouch这三种设备,其中iPho ...
- 团队项目-北航MOOC系统Android客户端 NABC
北航MOOC系统Android客户端 NABC (N) Need 需求 MOOC的全名是Massive Open Online Course,被称作大型开放式网络课程.2012年,美国的顶尖大学陆续设 ...
- InChatter系统之服务客户端的开发
今天终于开始客户端的开发了,客户端完成以后,我们将可以进行简单的交流.开发完成的程序只是一个很简单的雏形,在本系统完成以后,以及完成的过程中,大家都可以下载源码,在此基础上融入自己的想法和尝试,可以按 ...
- InChatter系统之服务器开发(一)
服务器端是整个消息系统的中枢,类似与人类的大脑.没有他,根本无法实现客户端之间的交流,为什么呢?这也涉及到我们的系统涉及,在服务器端,每个客户端的标识数据都会在服务器端进行保存,在这种情况下,当某一个 ...
- cas单点登录系统:客户端(client)详细配置
最近一直在研究cas登录中心这一块的应用,分享一下记录的一些笔记和心得.后面会把cas-server端的配置和重构,另外还有这几天再搞nginx+cas的https反向代理配置,以及cas的证书相关的 ...
- 分布式高性能消息处理中心HPMessageCenter
# HPMessageCenter 高性能消息分发中心.用户只需写好restful接口,在portal里面配置消息的处理地址,消息消费者就会自动访问相关接口,完成消息任务. ### 部署说明 **创建 ...
- cas单点登录系统:客户端(client)详细配置(包含统一单点注销配置)
最近一直在研究cas登录中心这一块的应用,分享一下记录的一些笔记和心得.后面会把cas-server端的配置和重构,另外还有这几天再搞nginx+cas的https反向代理配置,以及cas的证书相关的 ...
随机推荐
- Android-shareSDK
1.当数据: 地址:http://sharesdk.mob.com/Download 2.集成数据: DOS命令: java -jar QuickIntegrater.jar (输入自己的项目名 ...
- Hibernate 之 一级缓存
本篇文章主要是总结Hibernate中关于缓存的相关内容. 先来看看什么是缓存,我们这里所说的缓存主要是指应用程序与物流数据源之间(例如硬盘),用于存放临时数据的内存区域,这样做的目的是为了减少应用程 ...
- 编程题:1. var person = '{name:"Lily",sex:"famale",age:24,country:"US"}';将person转换成JSON对象并便利每个属性值。
/// <summary> /// Json工具类 /// </summary> public class JsonUtility { private static JsonU ...
- The uWSGI project aims at developing a full stack for building hosting services.
https://github.com/unbit/uwsgi-docs/blob/master/index.rst
- Spring Boot集成MyBatis与分页插件
Maven依赖: <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>p ...
- 在ubuntu18.0下安装qt4.7以及qt-creator安装过程中遇到的坑
最近的嵌入式Linux系统上要做课程设计= =要用贼老贼老的qt4.7,配环境踩坑都费了我1天时间.....所以记录下来,希望能给和我遇到相同问题的朋友一点帮助 apt-get install g++ ...
- 注册中心Eureka页面添加用户认证
我们需要登录即可访问到Eureka服务,这样其实是不安全的 为Eureka添加用户认证. 第一步,为itcast-microservice-eureka添加安全认证依赖: 第二步,增加applicat ...
- Lightoj 1020 - A Childhood Game
Allice先拿,最后拿球的输. Bob先拿,最后拿球的赢. 考虑Alice先拿球,当n=1时 Alice输 记dp[1]=0; n=2, dp[2]=1 n=3, dp[3]=1 因为n=1, ...
- YTU 2556: 空洞
2556: 空洞 时间限制: 1 Sec 内存限制: 128 MB 提交: 24 解决: 17 题目描述 春天来了,单身的霞姐越发地空虚寂寞,于是她想到一个办法,她认 为只要把英文字母上的洞都涂满 ...
- html5--7-33 阶段练习5
html5--7-33 阶段练习5 总结: 1.JS中可以递归函数 2.js中数组对象array的使用 学习要点 综合运用学过的知识完成三个综合小练习,巩固学过的知识. 阶段小练习5-1:使用递归算法 ...