一、模块结构

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

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. (转载)synchronized代码块

    原文:http://blog.csdn.net/luoweifu/article/details/46613015 作者:luoweifu 转载请标名出处 <编程思想之多线程与多进程(1)——以 ...

  2. Lightoj 1025 - The Specials Menu

    区间dp /* *********************************************** Author :guanjun Created Time :2016/6/30 23:2 ...

  3. Android 网络调试 adb tcpip 开启方法

    查看ip地址:adb shell ifconfig 1.连接USB数据线,打开usb调试,使用windows的“运行”命令行方式:(此方法需配置adb环境变量,也可直接进入adb工具目录执行\andr ...

  4. linux怎么区别文本文件和二进制文件

    linux的文本文件与二进制文件的区分与windows的区分是相同的!说到底计算机存储的文件都是以二进制形式存储的,但是区别是,习惯上认为: (1).文本文件 文本文件是包含用户可读信息的文件.这些文 ...

  5. Bootstrap 面板

    基本的面板:<div class="panel panel-default"> <div class="panel-body"> 这是一 ...

  6. ubuntu12.04中极品五笔简体繁体切换

    不小心切换成了繁体,按Ctrl+:,可以切换回来.

  7. 小程序 video 层级,原生组件

    原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上. 后插入的原生组件可以覆盖之前的原生组件. 原生组件还无法在 scroll-view.swiper. ...

  8. python的安装教学

    1.首先登陆到python的官方网站 https://www.python.org/ 2.鼠标放在Download上,点击下面对应的型号,我的是Windows 3.点击Windows到此页面,点击3. ...

  9. Luogu P1970 花匠 【线性Dp】 By cellur925

    题目描述 Description 花匠栋栋种了一排花,每株花都有自己的高度.花儿越长越大,也越来越挤.栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花 ...

  10. JavaScript编程艺术-第6章(JavaScript美术馆改进版)代码

    基于[第4章(JavaScript美术馆)代码]进行改进(***HTML与JS分离***) (*亲测可用) HTML: JS: CSS: