• SignalRMvc的简单例子


    1.介绍

      我们知道传统的http采用的是“拉模型”,也就是每次请求,每次断开这种短请求模式,这种场景下,client是老大,server就像一个小乌龟任人摆布,
    很显然,只有一方主动,这事情就没那么完美了,所以为了能够让server也能主动点,html5就应运而生了,或许大家都知道html5中有两种server的主动
    模型,第一种叫做websockect,也就是基于tcp模式的双工通讯,还有一种叫做SSE,也就是客户端来订阅服务器的一种事件模型,当然了,在html5出
    来之前,如果要做到服务器主动,我们只能采用变相的longpool和foreverframe勉强实现,而signalR这吊毛就是一个对他们进行了高层封装,也就是说
    signalR会在这四种技术中根据浏览器和服务器设置采取最优的一种模式,废话不多说,我们快速建立一个例子。

    2.快速搭建

    1.引入dll

    2.创建hub类(消息处理)

    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Hubs;
    using ServiceStack.Redis;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Web;
    
    namespace SignalRMvcDemo
    {
        [HubName("MessageHub")]
        public class MessageHub : Hub
        {
            //当前用户
            public static List<UserInfo> OnlineUsers = new List<UserInfo>(); // 在线用户列表
            RedisClient client = new RedisClient("192.168.10.134", 6379, "111111", 3);
    
            /// <summary>
            /// 登录连线
            /// </summary>
            /// <param name="userId">用户Id</param>
            /// <param name="userName">用户名</param>
            public void Register(string userName)
            {
                OnlineUsers = client.Get<List<UserInfo>>("list") ?? new List<UserInfo>();
                var connnectId = Context.ConnectionId;
                if (!OnlineUsers.Any(x => x.ConnectionId == connnectId))
                {
                    //添加在线人员
                    OnlineUsers.Add(new UserInfo
                    {
                        ConnectionId = connnectId,
                        UserName = userName,
                        LastLoginTime = DateTime.Now
                    });
                }
                // 所有客户端同步在线用户
                Clients.All.onConnected(connnectId, userName, OnlineUsers);
                client.Set<List<UserInfo>>("list", OnlineUsers);
            }
    
            /// <summary>
            /// 发送私聊
            /// </summary>
            /// <param name="toUserId">接收方用户ID</param>
            /// <param name="message">内容</param>
            public void SendPrivateMessage(string toConnectionId, string message)
            {
                OnlineUsers = client.Get<List<UserInfo>>("list") ?? new List<UserInfo>();
                var fromConnectionId = Context.ConnectionId;
    
                var toUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == toConnectionId);
                var fromUser = OnlineUsers.FirstOrDefault(x => x.ConnectionId == fromConnectionId);
    
                if (toUser != null)
                {
                    Clients.Client(toUser.ConnectionId).receivePrivateMessage(fromUser.ConnectionId, fromUser.UserName, message);
                }
                else
                {
                    //表示对方不在线
                    Clients.Caller.absentSubscriber();
                }
            }
    
            /// <summary>
            /// 全部发送
            /// </summary>
            /// <param name="message"></param>
            public void AllSend(string name, string message)
            {
                Clients.All.AllSend(name, message);
            }
    
            /// <summary>
            /// 连线时调用
            /// </summary>
            /// <returns></returns>
            public override Task OnConnected()
            {
                //Console.WriteLine("客户端连接,连接ID是:{0},当前在线人数为{1}", Context.ConnectionId, OnlineUsers.Count + 1);
                return base.OnConnected();
            }
    
            /// <summary>
            /// 断线时调用
            /// </summary>
            /// <param name="stopCalled"></param>
            /// <returns></returns>
            public override Task OnDisconnected(bool stopCalled)
            {
                OnlineUsers = client.Get<List<UserInfo>>("list")??new List<UserInfo>();
                var user = OnlineUsers.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId);
    
                // 判断用户是否存在,存在则删除
                if (user == null)
                {
                    return base.OnDisconnected(stopCalled);
                }
                // 删除用户
                OnlineUsers.Remove(user);
                Clients.All.onUserDisconnected(OnlineUsers);   //调用客户端用户离线通知
                client.Set<List<UserInfo>>("list", OnlineUsers);
    
                return base.OnDisconnected(stopCalled);
            }
    
            /// <summary>
            /// 重新连接时调用
            /// </summary>
            /// <returns></returns>
            public override Task OnReconnected()
            {
                return base.OnReconnected();
            }
        }
    
    
        public class UserInfo
        {
            public string ConnectionId { get; set; }
            public string UserName { get; set; }
            public DateTime LastLoginTime { get; set; }
        }
    }
    View Code

    3.Startup类(1.配置跨域 2.配置多实例) 

    using System;
    using System.Threading.Tasks;
    using Microsoft.Owin;
    using Owin;
    using Microsoft.AspNet.SignalR;
    using Microsoft.Owin.Cors;
    
    [assembly: OwinStartup(typeof(SignalRMvcDemo.StartupSignalR))]
    
    namespace SignalRMvcDemo
    {
        public class StartupSignalR
        {
            public void Configuration(IAppBuilder app)
            {
                //允许CORS跨域
                app.UseCors(CorsOptions.AllowAll);
                #region Redis配置
                //添加redis
                RedisScaleoutConfiguration redisScaleoutConfiguration = new RedisScaleoutConfiguration("192.168.10.134", 6379, "111111", "redis_signalr");
                //连接DB,默认为0
                redisScaleoutConfiguration.Database = 3;
                //SignalR用Redis
                GlobalHost.DependencyResolver.UseRedis(redisScaleoutConfiguration);
                #endregion
                // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888
                app.MapSignalR();//启动SignalR
            }
        }
    }
    View Code

    4.前端调用(引用hub生产的js文件,前端方法名称要与后端一致)

    <!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title></title>
        <meta charset="utf-8" />
        <link href="Content/bootstrap.min.css" rel="stylesheet" />
        <link href="Lib/toastr/toastr.min.css" rel="stylesheet" />
    </head>
    <body>
        <div class="panel panel-default">
            <div class="panel-body">
                <h1>分布式-消息推送测试</h1>
            </div>
        </div>
        <span>ConnectionId:</span>
        <input type="text" id="ConnectionId" readonly value="">
        <span>当前用户名称:</span>
        <input type="text" id="UserName" readonly value="">
        <hr>
        <span>在线用户数量:</span>
        <input type="text" id="userCount" readonly value="">
        <hr>
        <table class="table table-bordered">
            <thead>
                <tr>
                    <th>ConnectionId</th>
                    <th>UserName</th>
                </tr>
            </thead>
            <tbody id="tbody1"></tbody>
        </table>
        <span>接收用户:</span><select id="toUser"></select>
        <input type="text" id="message" />
        <input id="send" type="button" value="发送" />
        <input id="sendAll" type="button" value="发送消息(所有客户端)" />
        <script src="Scripts/jquery-1.10.2.min.js"></script>
        <script src="Lib/toastr/toastr.min.js"></script>
        <script src="Lib/iNotify/iNotify.js"></script>
        <script src="Scripts/bootstrap.min.js"></script>
        <script src="Scripts/jquery.signalR-2.2.2.js"></script>
        <script src='/SignalR/hubs'></script>
        <script type='text/javascript'>
            $(function () {
                $.connection.hub.url = 'http://localhost:10086/signalr';
                //引用自动生成的代理,MessageHub是HubName注解属性
                var work = $.connection.MessageHub;
    
                //对应后端的SendPrivateMessage函数,消息接收函数
                work.client.receivePrivateMessage = function (connectionId, user, message) {
                    //$('#messgaeInfo').append(message + '</br>');
                    toastr.info('发送内容:' + message, "发送人:" + user)
                    Notify.player();
                    Notify.setTitle(true);
                    Notify.setTitle('你有新的消息!');
                };
    
                //对应后端的SendMessage函数,消息接收函数
                work.client.AllSend = function (name, message) {
                    toastr.info('发送内容:' + message, "群发消息发生人:" + name)
                    Notify.player();
                    Notify.setTitle(true);
                    Notify.setTitle('你有新的消息!');
                };
    
                //后端SendLogin调用后,产生的loginUser回调
                work.client.onConnected = function (connnectId, userName, OnlineUsers) {
                    reloadUser(OnlineUsers);
                };
                work.client.onUserDisconnected = function (OnlineUsers) {
                    reloadUser(OnlineUsers);
                };
                //hub连接开启
                $.connection.hub.start().done(function () {
                    $('#UserName').val(prompt('请输入昵称:', ''));
                    var username = $('#UserName').val();
                    $('#ConnectionId').val($.connection.MessageHub.connection.id);
                    //发送上线信息
                    work.server.register(username);
    
                    //点击按钮,发送消息
                    $('#send').click(function () {
                        var friend = $('#toUser').val();
                        //调用后端函数,发送指定消息
                        work.server.sendPrivateMessage(friend, $("#message").val());
                    });
    
                    //点击按钮,发送消息
                    $('#sendAll').click(function () {
                        //调用后端函数,发送指定消息
                        work.server.allSend($('#UserName').val(), $("#message").val());
                    });
                });
            });
    
    
            //重新加载用户列表
            var reloadUser = function (userlist) {
                $("#tbody1").empty();
                $("#toUser").empty();
                $("#userCount").val(userlist.length);
                for (i = 0; i < userlist.length; i++) {
                    $("#tbody1").append("<tr><td>" + userlist[i].ConnectionId + "</td><td>" + userlist[i].UserName + "</td></tr>");
                    $("#toUser").append("<option value=" + userlist[i].ConnectionId + ">" + userlist[i].ConnectionId + ':[' + userlist[i].UserName + "]</option>");
                }
            }
    
            //toastr配置
            toastr.options = {
                closeButton: true,
                debug: false,
                progressBar: true,
                positionClass: "toast-bottom-right",
                onclick: null,
                showDuration: "300",
                hideDuration: "1000",
                timeOut: "5000",
                extendedTimeOut: "1000",
                showEasing: "swing",
                hideEasing: "linear",
                showMethod: "fadeIn",
                hideMethod: "fadeOut"
            };
    
            //iNotify配置
            var Notify = new iNotify({
                audio: {
                    file: ['Sound/msg.mp3']
                },
            });
        </script>
    </body>
    </html>
    View Code

    5.效果(支持跨域,需要有redis)

    3.项目下载路径 https://github.com/lgxlsm/SignalRMvcDemo

  • 相关阅读:
    CodeForces 1294B Collecting Packages(排序+贪心)
    计算系数(组合数)
    垒骰子(矩阵快速幂)
    蒜头君倒水(矩阵快速幂)
    Buy Tickets POJ
    Billboard HDU
    树状数组求逆序对 附HDU1394
    codeforces 1304D Shortest and Longest LIS
    codeforces 1301C Ayoub's function
    Codeforces 1301B Motarack's Birthday(二分)
  • 原文地址:https://www.cnblogs.com/lgxlsm/p/7490139.html
Copyright © 2020-2023  润新知