C#项目集成SignalR

1、什么是SugnalR?

       ASP. NET Signal是为ASP.NET开发人员提供的一个库,可以简化开发人员将实时Web功能添加到应用程序的过程。实时Web功能是指这样一种功能:当所连接的客户端变得可用时服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。

       我个人的理解是:当客户端向服务器端发起一次请求,建立连接之后,当服务器端数据发生了变化,无需客户端再次发起请求,服务器端即可将更新后的数据主动推送给客户端。实际工作中可以用它做很多事情,如果用户是通过刷新web页面,来查看新的数据,或者是通过页面实现长轮询来检索新的数据,那么就该考虑使Signal了。示例包括仪表板和监视应用程序、协作应用程序(例如同时编辑文档)、工作进度更新和实时表单等等。

       Signal会自动管理连接,并允许您像Chat室那样向所有连接的客户端同时发送消息。你也可以向特定的客户端发送消息。客户端和服务器之间的连接是持久性的,不像传统的HITP连接每个通信都需要重新建立一个连接Signal支持“服务器推送”功能,即服务器代码可以使用远程过程调用(PRC)来调用浏览器中的客户端代码,而不使用目前在Web上常用的请求ー响应模型Signal应用程序可以通过使用服务总线。SQL Server或 Redis扩展到数以千计的客户端Signal是开源的,可以通过 Github访问。

2、为什么要用SignalR?(我的使用场景)

由于VFS系统功能逻辑较为复杂,某些功能操作后等待时间较长,可以运用SignalR来减少使用者在等待返回结果上的时间浪费。例如:对账单刷新功能,此功能需要刷新报表中的相关结算单位的当月的对账单明细、对账单汇总的数据,由于报表的逻辑较为复杂,因此如果结算单位单量很大的情况下刷新的过程比较长,因此引入SignalR,当客户端运行时会首先与服务器建立连接,发起对账单刷新请求时,会异步执行数据的刷新操作,异步执行的过程中会直接返回“系统正在刷新数据”的通知消息,此时,使用者不必在此等候,可先去做其他工作,等数据刷新执行完毕后,服务器会主动向客户端发起消息通知,通知客户端对账单刷新已完成。

3、怎么用SignalR?

Demo下载地址(可点击此处下载

服务器端:

(1)在项目文件夹中新建项目,命名为SignalR

注意:新建的SignalR的目标框架要与原有的框架版本一致

(2)在此项目中安装SignalR相关的nuget包:

Microsoft.AspNet.SignalR/Microsoft.AspNet.SignalR.Core/Microsoft.AspNet.SignalR.JS等

(3)在Startup.cs项目启动文件中加入SignalR的启动配置

app.Map("/signalrapi", map =>
            {
                // 跨域支持
                map.UseCors(CorsOptions.AllowAll);
                var hubConfiguration = new HubConfiguration
                {

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

注:需要引入包using Microsoft.AspNet.SignalR; 和  using Microsoft.Owin.Cors;

(4)在新建的SingnalR项目中新建文件夹MsgHubs,并在此文件夹下新建类MsgHub,此类需集成Hub类(Microsoft.AspNet.SignalR.Hub)。此类用于写客户端与服务器端交互的公用方法,例如:客户端启动或刷新时调用服务器端记录当前登陆人信息

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>
        /// 客户端调用服务器,记录用户唯一标识
        /// </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)新建的项目中都会默认有一个Class类,可将其重命名用于写向指定用户发送请求的公用方法

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>
        /// 向指定用户发送消息
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public WebApiResult Send(string userName, MessageInfo msgInfo)
        {
            var result = new WebApiResult();
            try
            {
                //此处需引入MsgHub类
                if (MsgHub._clients.ContainsKey(userName))
                {
                    var connectId = MsgHub._clients[userName];
                   //发送到指定客户端
                    //让客户端获取最新的消息
                    Chat.Clients.Client(connectId).getNewMessage(msgInfo);
                    //Chat.Clients.Client(connectId).serverToClient(msgInfo+"  "+DateTime.Now.ToString("yyyy-MM-dd"));
                    //发送到所有客户端
                    //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)新建Ctroller&Service专门用于消息的记录与发送

例如:对账单刷新

/// <summary>
/// 对账单刷新
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[ActionName("BillInfoRefresh")]
[HttpPost]
public WebApiResult BillInfoRefresh (CustConfirmDetailModel model)
{
    var result = new WebApiResult();
    //异步执行,执行完毕后会将执行结果反馈到客户端
    _messageService.BillInfoRefreshTast(model);
    return result;
}

注:异步方法无法获取HttpContext.Current,此值为空,在获取CurrentUser信息时会报错,因此,此处可将异步方法写在方法体内

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 = $"对账单刷新失败!错误信息:{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));
                }
                // 对账单汇总
                var res = _reportService.InsertCustConfirmInfo(model);
                if (res.Success)
                {
                    // 最账单明细汇总
                    var res_mx = _reportService.InsertCustConfirmDetail(model);
                    sys_message msgInfo = new sys_message()
                    {
                        Message = "对账单刷新成功!",
                        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));
                }
                else
                {
                    sys_message msgInfo = new sys_message()
                    {
                        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);
            });
        }

用户消息管理方法,获取和标记已读供前台调用

客户端:

1、安装nuget包:Microsoft.AspNet.SignalR.JS

2、配置相关js

 

<script src="~/Scripts/jquery.signalR-2.4.1.min.js"></script>
<script src="@System.Configuration.ConfigurationManager.AppSettings["ApiBaseUrl"]/signalrapi/hubs"></script>
<!-- 消息提示控件的js -->
<script src="~/Content/js/message/message.common.js"></script>
<script src="~/Content/js/message/message.directives.js"></script>

<script type="text/javascript">
    /*初始化SignalR*/
    //$(function () {
    //    // 申明一个Hub代理引用,首字母小写
    //    var hub = $.connection.msgHub;
    //    // 服务端调用客户端
    //    hub.client.serverToClient = function (message) {
    //        console.log("message:", message);
    //    }
    //    // signalr/hubs桥接
    //    $.connection.hub.url = apiBaseUrl + "signalrapi";
    //    // 启用Hub事件的日志记录
    //    $.connection.hub.logging = true;
    //    // 启动Hub连接,指定传输协议
    //    $.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>

注:近期有很多朋友想要加qq跟我探讨交流,因此我建立了一个技术交流沟通群,另外群内也会分享一些好的技术资源,大家感兴趣的可以进群,此项目的源码在群文件中也可找到(群号码:1055109975,可扫描下方二维码进群)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值