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評價是非常不錯的,完全可以做企業級的分佈式實時應用,有興趣的讀者可以訪問官方站點了解。

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