LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(六)之SignalR与MVC结合封装消息发送与接收

前言

本系列文章特点:使用ASP.NET SignalR和LayIM快速入门对接,实现一对一聊天,群聊,添加聊天群组,查找聊天记录等功能。源代码不包含LayIM的源代码,因为官方并没开源属于收费资源,所以得遵从官方的规则,但包含Demo的数据库脚本和改造之后的find.html,源代码在最后一节。

文章目录:

LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(一)之效果展示与关键技术简介

LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(二)之后台数据库创建

LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(三)之LayIM初始化数据

LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(四)之ASP.NET SignalR核心功能介绍

LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(五)之使用RabbitMQ缓存消息

LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(六)之SignalR与MVC结合封装消息发送与接收

LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(七)之LayIM与MVC数据交互实现单聊和群聊

LayIM 3.9.1与ASP.NET SignalR实现Web聊天室快速入门(八)之改造查找页面实现拉取好友创建群

一、本文的目标与简介

在前面文章已经讲述了集线器以及RabbitMQ相关的技术点,本文就主要针对LayIM的几个主要功能,消息发送,图片文件上传以及消息接收封装三个Action工LayIM前端调用。

二、封装BaseHubController

这个类的作用主要是方便其他继承与它的Controller方便的获取创建的Hub,以实现利用Clients和Groups进行消息处理。代码如下:

    public class BaseHubController<T> : Controller where T : Hub
    {
        public IHubConnectionContext<dynamic> Clients { get; set; }
        public IGroupManager Groups { get; set; }
        public BaseHubController()
        {
            var hub = GlobalHost.ConnectionManager.GetHubContext<T>();
            Clients = hub.Clients;
            Groups = hub.Groups;
        }
    }

三、LIMController实现消息处理

这个Controller继承BaseHubController,它主要包含以下三个Action,这里会涉及到前文所说的Hub的ConnectionId与数据库用户表主键的对应关系,所以这里首先创建一个安全的Dictionary,前文已经介绍过,就不再介绍这个Dictionary的作用,这里直接贴出代码:

    public static class LIMUserTable
    {
        public static readonly ConcurrentDictionary<int, string> diclist = new ConcurrentDictionary<int, string>();

        public static void AddUser(int key, string value)
        {
            if (diclist.ContainsKey(key))
            {
                diclist[key] = value;
            }
            else
            {
                diclist.TryAdd(key, value);
            }
        }

        public static string GetValueByKey(int key)
        {
            if (diclist.ContainsKey(key))
            {
                return diclist[key];
            }
            else
            {
                return "";
            }
        }
    }

LIMUserTable有两个方法,一个用来添加数据,一个用来取数据即用作根据用户主键获取当前的ConnectionId。

接下来重点介绍LIMController的三个方法

1.AddConnectionId(string connectionId)

这个方法在前文也提到过,在前端获取到当前用户的ConnectionId时把ConnectionId提交到这个方法里,同时在这个方法里还要做两件事:第一件事就是把当前的ConnectionId添加到用户所有的群组,即所有的群组内用户上线,第二件事:处理ConnectionId接收到的消息,其中涉及到前文提到的RabbitMQReceive自定义的消息监听取出,所以代码如下:

        public ActionResult AddConnectionId(string connectionId)
        {
            try
            {
                int userid = int.Parse(Session["UserId"].ToString());
                LIMUserTable.AddUser(userid, connectionId);//将用户的connectionId存储起来
                RabbitMQReceive customer = new RabbitMQReceive();
                //开始监听
                customer.BindReceiveMqMsg("single_" + userid.ToString());
                customer.ReceiveCallback = message =>
                {
                    connectionId = LIMUserTable.GetValueByKey(userid);
                    Clients.Client(connectionId).receiveMsg(message);
                    return true;
                };
                var grouplist = LIMRepository.GetUserRoomList(userid);
                foreach (var item in grouplist) //所有的群组上线
                {
                    Groups.Add(connectionId, item.id.ToString());
                }
                return Json(new ReturnDoEntity { result = true, message = "添加成功" }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                return Json(new ReturnDoEntity { result = false, message = ex.Message }, JsonRequestBehavior.AllowGet);
            }

        }

2.SendMessage(int fid, int tid, MessageDoEntity msg)

这个方法用来发送消息,即消息是谁发给谁,发了什么消息,其中MessageDoEntity是LayIM要求的消息的数据格式,代码如下:

    /// <summary>
    /// 发送消息对应的实体
    /// </summary>
    public class MessageDoEntity
    {   /// <summary>
        /// 消息来源类型
        /// 系统消息为ture
        /// </summary>
        public bool system { get; set; } = false;
        /// <summary>
        /// 消息来源用户名
        /// </summary>
        public string username { get; set; }
        /// <summary>
        /// 消息来源用户头像
        /// </summary>
        public string avatar { get; set; }
        /// <summary>
        /// 消息的来源ID(如果是私聊,则是用户id,如果是群聊,则是群组id)
        /// </summary>
        public string id { get; set; }
        /// <summary>
        /// 聊天窗口来源类型,从发送消息传递的to里面获取
        /// 单人:friend 群组:group
        /// </summary>
        public string type { get; set; }
        /// <summary>
        /// 消息内容
        /// </summary>
        public string content { get; set; }
        /// <summary>
        /// 消息id,可不传。除非你要对消息进行一些操作(如撤回)
        /// </summary>
        public int cid { get; set; }
        /// <summary>
        ///是否我发送的消息,如果为true,则会显示在右方
        /// </summary>
        public bool mine { get; set; }
        /// <summary>
        /// 消息的发送者id(比如群组中的某个消息发送者),可用于自动解决浏览器多窗口时的一些问题
        /// </summary>
        public string fromid { get; set; }
        /// <summary>
        /// 服务端时间戳毫秒数。注意:如果你返回的是标准的 unix 时间戳,记得要 *1000,13位
        /// </summary>
        public long timestamp { get; set; }
        /// <summary>
        /// 是否显示‘前后消息’
        /// </summary>
        public string beforemsg { get; set; }
    }

LayIM的消息有两种类型即friend和group,根据这两种类型,做不同的处理,代码如下:

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="fid">发送者</param>
        /// <param name="tid">接收者</param>
        /// <param name="msg"></param>

        [HttpPost]
        public void SendMessage(int fid, int tid, MessageDoEntity msg)
        {
            DateTime ndt = DateTime.Now;//当前时间
            msg.timestamp = CommonHelper.GetTimeSpan(ndt);
            List<MessageEntity> meglist = new List<MessageEntity>();
            meglist.Add(new MessageEntity()
            {
                FUserId = fid,
                TUserId = tid,
                SendTime = ndt,
                MessageContent = msg.content
            });
            string strmsg = CommonHelper.SerializeObject(msg);
            if (msg.type == "friend")
            {
                RabbitMQSend.PushMessage("single_" + tid.ToString(), strmsg);
                Task.Run(() => LIMRepository.SaveMessage(meglist));
            }
            else if (msg.type == "group")
            {
                ///查找当前群组的人
                string connectionId = LIMUserTable.GetValueByKey(fid);
                ///向群组添加消息
                Clients.Group(msg.id, connectionId).receiveMsg(strmsg);//消息的来源ID(如果是私聊,则是用户id,如果是群聊,则是群组id)
                Task.Run(() => LIMRepository.SaveRoomchat(meglist));
            }
        }

这里需要注意:本Demo是把“single_”+用户的主键作为消息队列的队列名称,所以取得时候也是按照这个名称取,group的名称也直接就是群组的主键,即对应数据库表LIM.Room的主键RoomId。

3.UploadFileAndImg()

这个Action主要是用来处理LayIM上传的文件和图片,同样LayIM对上传文件的返回数据也有格式要求即本Demo的UploadResultDoEntity实体类模型,代码如下:

    /// <summary>
    /// 上传文件或者图片返回实体模型
    /// </summary>
    public class UploadResultDoEntity
    {
        /// <summary>
        /// 0表示成功,其它表示失败
        /// </summary>
        public int code { get; set; } = 0;
        /// <summary>
        /// 失败信息
        /// </summary>
        public string msg { get; set; }
        /// <summary>
        /// 文件信息
        /// </summary>
        public FileInfo data { get; set; } = new FileInfo();
    }
    public class FileInfo
    {
        /// <summary>
        /// 文件地址
        /// 如:"http://cdn.xxx.com/upload/file/xxx.zip" 
        /// </summary>
        public string src { get; set; }
        /// <summary>
        /// 文件名称
        /// </summary>
        public string name { get; set; }
    }

UploadFileAndImg的代码如下:

        [ValidateInput(false)]
        [HttpPost]
        public ActionResult UploadFileAndImg()
        {
            UploadResultDoEntity uploadResult = new UploadResultDoEntity();

            try
            {
                if (Request.Files.Count > 0)
                {
                    HttpPostedFileBase Portrait = Request.Files[0];
                    string fileName = Path.GetFileName(Portrait.FileName).Replace("&", "");
                    string newfilename = Guid.NewGuid().ToString("N") + "-" + fileName;
                    string serverpath = "/IMFiles/" + DateTime.Now.ToString("yyyy") + "/" + DateTime.Now.ToString("MM");
                    var sysPath = Server.MapPath(serverpath);
                    if (!Directory.Exists(sysPath)) Directory.CreateDirectory(sysPath);
                    string savePath = Path.Combine(sysPath, newfilename);
                    Portrait.SaveAs(savePath);
                    uploadResult.data.src = serverpath + "/" + newfilename;
                    uploadResult.data.name = fileName;
                }
            }
            catch (Exception ex)
            {
                uploadResult.code = -1;
                uploadResult.msg = ex.Message;
            }

            return Json(uploadResult);
        }

四、总结

这一节主要是讲述了如何在MVC中实现和Hub结合实现消息发送与接收,额外的添加了使用RabbitMQ缓存消息,下一节将展示如何使用LayIM和MVC的Action进行数据交互。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值