SignalR 实时通知消息并行推送和批量存储实现

前言:SignalR是基于.NET平台Web应用的实时消息通讯框架,有人称之为.NET平台的.NodeJS;可用于Web页面聊天,消息推送等功能实现。本文摘取部分代码,利用.NET平台的Parallel功能实现通知消息的并行推送和批量存储。


1. 接收通知消息的Api接口:

MVC 控制器代码:

[HttpPost]
[AllowAnonymous]
public void Notify(Message message)
{
    var msgModel = new MessageModel();
    msgModel.Notify(message);
}

[HttpPost]
[AllowAnonymous]
public void Notify(List<Message> msgList)
{
    var msgModel = new MessageModel();
    msgModel.BatchNotify(msgList);
}	


2. 通知消息的并行推送:

2.1 批量推送接口

首先调用到Task.Factory.StartNew()方法创建新任务,用BulkCopy()方法将数据批量插入到数据库;然后并行推送消息,因为消息接收人有多个,根据消息接收人的消息实体对象列表,Parallel.ForEach()对每条消息并行推送到Web用户的前端。

/// <summary>
/// 通知单条消息
/// </summary>
/// <param name="msg"></param>
public void Notify(Message msg)
{
    List<Message> msgList = new List<Message>();
    msgList.Add(msg);
    BatchNotify(msgList);
}

/// <summary>
/// 多条消息列表推送
/// </summary>
/// <param name="msgList"></param>
public void BatchNotify(List<Message> msgList)
{
    //批量插入消息
    var msgService = new MessageService();
    Task.Factory.StartNew(() =>
    {
        msgService.BulkInsert(msgList);
    });

    IList<string> onlineConnectionIds = new List<string>();
    var hub = GlobalHost.ConnectionManager.GetHubContext<ClientPushHub>();
    var onlineUsers = ChatHub.GetOnlineUsersOnHub();

    //发送消息
    Parallel.ForEach<Message>(msgList, (msg) => 
    { 
        PushMessage(msg, onlineUsers, hub); 
    });
}



2.2 调用SignalR 接口给在线用户发送通知消息

每条消息有多个接收人,每个接收人在前端的Connection连接存储在ConnectionIds集合中,遍历进行推送。

/// <summary>
/// 单条消息推送服务
/// </summary>
/// <param name="message">消息数据</param>
private void PushMessage(Message msg, List<User> onlineUsers, IHubContext hub)
{
    User user = null;
    List<RecieverEntity> recievers = msg.Recievers;
    foreach (var reciever in recievers)
    {
        user = onlineUsers.SingleOrDefault(a => a.Name == reciever.Reciever);
        if (user != null)
        {
            foreach (var connId in user.ConnectionIds)
            {
                hub.Clients.Client(connId).onPushingMessage(new
                {
                    sender = msg.Sender,
                    msgTitle = msg.MsgTitle,
                    msgContent = msg.MsgContent,
                    billUrl = msg.BillUrl,
                    iframeTxt = msg.IframeTxt,
                    iframeCode = msg.IframeCode,
                    sendTime = DateTime.Now.ToString(),
                    sendType = "notification"
                });
            }
        }
    }
}


2.3 客户端接收通知消息

//接收系统服务通知消息
clientPushHub.client.onPushingMessage = function (message) {
    popNewMsgHintWindow(message);
}

3. 批量消息的批量存储

3.1 批量插入

/// <summary>
/// 批量插入
/// </summary>
/// <param name="msgList"></param>
public void BulkInsert(List<Message> msgList)
{
    var msgTable = MsgBatchUtility.GetTableSchema();
    foreach (var msg in msgList)
    {
        Insert(msgTable, msg);
    }
    MsgBatchUtility.BulkCopy(msgTable);
}

3.2  获取消息表结构

/// <summary>
/// 获取数据表Schema
/// </summary>
/// <returns></returns>
public static DataTable GetTableSchema()
{
    DataTable dt = new DataTable();
    dt.Columns.AddRange(new DataColumn[]{
        new DataColumn("MsgID", typeof(int)),
        new DataColumn("MsgType", typeof(byte)),
        new DataColumn("MsgTitle", typeof(string)),
        new DataColumn("MsgContent", typeof(string)),
        new DataColumn("Status", typeof(byte)),
        new DataColumn("SenderID", typeof(string)),
        new DataColumn("Sender", typeof(string)),
        new DataColumn("SendTime", typeof(DateTime)),
        new DataColumn("RecieverID", typeof(string)),
        new DataColumn("Reciever", typeof(string)),
        new DataColumn("RecievedTime", typeof(DateTime)),
        new DataColumn("AppName", typeof(string)),
        new DataColumn("AppInstanceID", typeof(string)),
    });
    return dt;
}



3.3 数据库批量拷贝方法BulkCopy()

/// <summary>
/// 批量插入方法
/// </summary>
/// <param name="dt"></param>
public static void BulkCopy(DataTable dt)
{
    SqlConnection sqlConn = new SqlConnection(connectionString);
    SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlConn);
    bulkCopy.DestinationTableName = "dbo.im_message";
    bulkCopy.BatchSize = dt.Rows.Count;
    try
    {
        sqlConn.Open();
        if (dt != null && dt.Rows.Count != 0)
            bulkCopy.WriteToServer(dt);
    }
    catch (Exception)
    {
        throw;
    }
    finally
    {
        sqlConn.Close();
        if (bulkCopy != null)
            bulkCopy.Close();
    }
}



总结:


本文暂时没有对SignalR的用法和在线用户列表维护做出代码示例,会在后期文章中单独列出,SiganlR功能在做WebQQ聊天功能,网站页面聊天,聊天室功能时非常有用,有兴趣的开发人员可以以此为框架,搭建自己的实时通讯的工具,至于性能方法,SignalR评价是非常不错的,完全可以做企业级的分布式实时应用,有兴趣的读者可以访问官方站点了解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章