C. project integration SignalR

1. What is SugnalR?

ASP.NET signal is a library for ASP.NET developers, which can simplify the process of adding real-time Web functions to applications. The real-time Web function refers to the function that the server code can push the content to the connected client immediately when it becomes available, instead of letting the server wait for the client to request new data.

My personal understanding is: when the client sends a request to the server and establishes a connection, when the data on the server changes, the server can actively push the updated data to the client without the client sending a request again. In practice, we can use it to do a lot of things. If users refresh web pages to view new data, or retrieve new data through long polling, then we should consider making Signal. Examples include dashboards and monitoring applications, collaborative applications such as editing documents at the same time, work progress updates, real-time forms, and more.

Signal will automatically manage the connection and allow you to send messages to all connected clients at the same time like Chat room. You can also send messages to specific clients. The connection between the client and the server is persistent. Unlike the traditional HITP connection, each communication needs to be re established. Signal supports the "server push" function, that is, the server code can use the remote procedure call (PRC) to call the client code in the browser, Instead of using the request response model commonly used on the Web, the signal application can use the service bus. SQL Server or Redis extends to thousands of clients. Signal is open source and can be accessed through Github.

2. Why use SignalR? (my usage scenario)

Due to the complex function logic of VFS system and the long waiting time after some function operations, SignalR can be used to reduce the time waste of users waiting for the returned results. For example, the refresh function of reconciliation document needs to refresh the statement details and summary data of the current month of the relevant settlement company in the report. Because the logic of the report is complex, the refresh process is relatively long in case of a large number of settlement company documents. Because of the introduction of SignalR, when the client is running, it will first establish a connection with the server and initiate the brush of reconciliation document When a new request is made, the data refresh operation will be performed asynchronously. In the process of asynchronous execution, the notification message "the system is refreshing data" will be returned directly. At this time, the user does not have to wait here, but can do other work first. After the data refresh is completed, the server will send a message notification to the client to inform the client that the refresh of reconciliation sheet has been completed.

3. How to use SignalR?

Demo download address (click here to download)

Server side:

(1) Create a new project in the project folder named SignalR

Note: the target framework of the new SignalR should be consistent with the original framework version

(2) To install SignalR related nuget packages in this project:

Microsoft.AspNet.SignalR/Microsoft.AspNet.SignalR.Core/Microsoft.AspNet.SignalR.JS, etc

(3) Add the startup configuration of SignalR in the Startup.cs project startup file

app.Map("/signalrapi", map =>
            {
                // Cross domain support
                map.UseCors(CorsOptions.AllowAll);
                var hubConfiguration = new HubConfiguration
                {

                };
                map.RunSignalR(hubConfiguration);
            });

Note: it is necessary to introduce the package using Microsoft.AspNet.SignalR; and using Microsoft.Owin.Cors;

(4) Create a new folder MsgHubs in the new SingnalR project, and create a new class MsgHub under this folder. This class needs to integrate the hub class (Microsoft.AspNet.SignalR.Hub). This class is used to write a common method for the interaction between the client and the server. For example, when the client starts or refreshes, it calls the server to record the current login information

using Microsoft.AspNet.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SignalR.MsgHubs
{
    public class MsgHub : Hub
    {
        public static dynamic client { get; set; }
        public static Dictionary<string, string> _clients = new Dictionary<string, string>();

        /// <summary>
        ///The client calls the server to record the unique identity of the user
        /// </summary>
        /// <param name="message"></param>
        public void ClientToServer(string message)
         {
            if (!_clients.ContainsKey(message))
            {
                _clients.Add(message, Context.ConnectionId);
            }
            else
            {
                _clients.Remove(message);
                _clients.Add(message, Context.ConnectionId);
            }
        }

    }
}

(5) There will be a Class class in the new project by default, which can be renamed to write the common method used to send the request to the specified user

using Lunz.Services;
using Microsoft.AspNet.SignalR;
using SignalR.MsgHubs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SignalR
{
    public class MsgHelper
    {
        private static IHubContext _chat;

        public static IHubContext Chat
        {
            get
            {
                if (_chat == null)
                {
                    _chat = GlobalHost.ConnectionManager.GetHubContext<MsgHub>();
                }
                return _chat;
            }
        }

        private static MsgHelper _current;

        public static MsgHelper Current
        {
            get
            {
                if (_current == null)
                {
                    _current = new MsgHelper();
                }
                return MsgHelper._current;
            }
        }

        /// <summary>
        ///Send message to specified user
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public WebApiResult Send(string userName, MessageInfo msgInfo)
        {
            var result = new WebApiResult();
            try
            {
                //The MsgHub class needs to be introduced here
                if (MsgHub._clients.ContainsKey(userName))
                {
                    var connectId = MsgHub._clients[userName];
                   //Send to specified client
                    //Let the client get the latest message
                    Chat.Clients.Client(connectId).getNewMessage(msgInfo);
                    //Chat.Clients.Client(connectId).serverToClient(msgInfo+"  "+DateTime.Now.ToString("yyyy-MM-dd"));
                    //Send to all clients
                    //Clients.All.serverToClient(message + "  " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                }
            }
            catch
            {
            }
            return result;
        }
    }
}


public class MessageInfo
{
    public int Id { get; set; }
    public string Message { get; set; }
    public Nullable<System.DateTime> SendAt { get; set; }
    public Nullable<System.Guid> ReceiveUserId { get; set; }
    public string ReceiveUserName { get; set; }
    public string ReceiveUserCode { get; set; }
    public bool IsRead { get; set; }
    public Nullable<System.DateTime> ReadTime { get; set; }
    public Nullable<System.DateTime> InsertTime { get; set; }
    public bool Deleted { get; set; }
}

(6) New ctroller & service is specially used for message recording and sending

For example: refresh reconciliation doc

/// <summary>
///Refresh reconciliation doc
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[ActionName("BillInfoRefresh")]
[HttpPost]
public WebApiResult BillInfoRefresh (CustConfirmDetailModel model)
{
    var result = new WebApiResult();
    //Asynchronously execute. After execution, the execution result will be fed back to the client
    _messageService.BillInfoRefreshTast(model);
    return result;
}

Note: the asynchronous method cannot get HttpContext.Current. This value is empty. An error will be reported when getting CurrentUser information. Therefore, the asynchronous method can be written in the method body here

public void BillInfoRefreshTast(CustConfirmDetailModel model)
        {
            var result = new WebApiResult();
            MessageModel message = new MessageModel();
            List<sys_message> messageList = new List<sys_message>();
            var curUserId = CurrentUser?.UserId;
            var curUserName = CurrentUser?.Username;
            var curUserCode = CurrentUser?.DisplayName;
            Task.Run(() =>
            {
                var check = _exportService.UserPermissionInfoById(model);
                if (!check.Success)
                {
                    result.AddError(check.AllMessages);
                    sys_message msgInfo = new sys_message() {
                        Message = $"Failed to refresh reconciliation doc! Error message:{result.AllMessages}",
                        SendAt = DateTime.Now,
                        ReceiveUserId = curUserId,
                        ReceiveUserName = curUserName,
                        ReceiveUserCode = curUserCode,
                        IsRead = false,
                        InsertTime = DateTime.Now
                    };
                    messageList.Add(msgInfo);
                    MsgHelper.Current.Send(curUserName, Mapper.Map<MessageInfo>(msgInfo));
                }
                // Statement summary
                var res = _reportService.InsertCustConfirmInfo(model);
                if (res.Success)
                {
                    // Summary of most bill details
                    var res_mx = _reportService.InsertCustConfirmDetail(model);
                    sys_message msgInfo = new sys_message()
                    {
                        Message = "Reconciliation document refreshed successfully!",
                        SendAt = DateTime.Now,
                        ReceiveUserId = curUserId,
                        ReceiveUserName = curUserName,
                        ReceiveUserCode = curUserCode,
                        IsRead = false,
                        InsertTime = DateTime.Now
                    };
                    messageList.Add(msgInfo);
                    //Send statement summary success message
                    MsgHelper.Current.Send(curUserName, Mapper.Map<MessageInfo>(msgInfo));
                }
                else
                {
                    sys_message msgInfo = new sys_message()
                    {
                        Message = $"Failed to refresh reconciliation doc! error message{res.AllMessages}",
                        SendAt = DateTime.Now,
                        ReceiveUserId = curUserId,
                        ReceiveUserName = curUserName,
                        ReceiveUserCode = curUserCode,
                        IsRead = false,
                        InsertTime = DateTime.Now
                    };
                    messageList.Add(msgInfo);
                    MsgHelper.Current.Send(curUserName, Mapper.Map<MessageInfo>(msgInfo));
                }
                message.MessageList = messageList;
                this.InsertSysMessage(message);
            });
        }

User message management method, get and mark read for foreground call

Client:

1. Install nuget package: Microsoft.AspNet.SignalR.JS

2. Configuration related js

3. Message prompt control

<script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
<script src="@System.Configuration.ConfigurationManager.AppSettings["ApiBaseUrl"]/signalrapi/hubs"></script>
<!-- Message prompt control's js -->
<script src="~/Content/js/message/message.common.js"></script>
<script src="~/Content/js/message/message.directives.js"></script>

<script type="text/javascript">
    /*Initialize SignalR*/
    //$(function () {
    //    //Declare a Hub proxy reference, initial lowercase
    //    var hub = $.connection.msgHub;
    //    //Server calls client
    //    hub.client.serverToClient = function (message) {
    //        console.log("message:", message);
    //    }
    //    //Signal / hub bridging
    //    $.connection.hub.url = apiBaseUrl + "signalrapi";
    //    //Enable logging of Hub events
    //    $.connection.hub.logging = true;
    //    //Start Hub connection, specify transport protocol
    //    $.connection.hub.start({ transport: ['webSockets', 'longPolling'] }).done(function () {
    //        hub.server.clientToServer("zhaoqian");
    //    });
    //});

    /* Init Metronic's core jquery plugins and layout scripts */
    $(document).ready(function () {
        Metronic.init(); // Run metronic theme
        Metronic.setAssetsPath('/content/assets/'); // Set the assets folder path
    });
</script>

 

36 original articles published, 30 praised, 60000 visitors+
Private letter follow

Tags: JQuery SQL Redis github

Posted on Tue, 17 Mar 2020 02:41:35 -0700 by vijayfreaks