zoukankan      html  css  js  c++  java
  • .NET4.x下使用SignalR做登录、推送

    .NET Core平台下记录过一篇文章了:https://www.cnblogs.com/shousiji/p/12737925.html

    已经不想在.net framework下折腾了,奈何老项目也需要SignalR,故写下这篇文章。

    官方示例:MVC方式前后端分离方式-后端前后端分离方式-前端

    前后端方式复杂些,本文就是记录总结这个方式。项目结构如图:

    一、创建服务端

    1. 在vs中创建一个空的“web应用程序”,命令为“SignalRServer”

    2. NuGet搜索并安装“Microsoft.AspNet.SignalR”

     3. 会自动下载Scripts文件夹,待会把它剪切到“SignalRClient”项目中

     4. NuGet搜索并安装“Microsoft.Owin.Cors”跨域组件

     5. 新建OwinStartup类,命名为“Startup.cs”

     

    代码如下:

    using Microsoft.AspNet.SignalR;
    using Microsoft.Owin;
    using Microsoft.Owin.Cors;
    using Owin;
    
    [assembly: OwinStartup(typeof(SignalRServer.Startup))]
    
    namespace SignalRServer
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                // Branch the pipeline here for requests that start with "/signalr"
                app.Map("/signalr", map =>
                {
                    // Setup the CORS middleware to run before SignalR.
                    // By default this will allow all origins. You can 
                    // configure the set of origins and/or http verbs by
                    // providing a cors options with a different policy.
                    map.UseCors(CorsOptions.AllowAll);
                    var hubConfiguration = new HubConfiguration
                    {
                        // You can enable JSONP by uncommenting line below.
                        // JSONP requests are insecure but some older browsers (and some
                        // versions of IE) require JSONP to work cross domain
                        // EnableJSONP = true
                    };
                    // Run the SignalR pipeline. We're not using MapSignalR
                    // since this branch already runs under the "/signalr"
                    // path.
                    map.RunSignalR(hubConfiguration);
                });
            }
        }
    }

     6. 新建类,命名为“DemoChatHub.cs”,代码如下:

    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Hubs;
    using Newtonsoft.Json;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    
    namespace SignalRServer
    {
        [HubName("demoChatHub")]
        public class DemoChatHub : Hub
        {
            /// <summary>
            /// 已登录的用户信息
            /// </summary>
            public static List<UserModel> OnlineUser { get; set; } = new List<UserModel>();
    
            /// <summary>
            /// 模拟存放在数据库里的用户信息
            /// </summary>
            private static readonly List<UserModel> _dbuser = new List<UserModel> {
              new UserModel{
                UserName = "test1", Password = "111", GroupName = "Group1"
              },
              new UserModel{
                UserName = "test2", Password = "111", GroupName = "Group2"
              },
              new UserModel{
                UserName = "test3", Password = "111", GroupName = "Group2"
              },
              new UserModel{
                UserName = "test4", Password = "111", GroupName = "Group1"
              },
              new UserModel{
                UserName = "test5", Password = "111", GroupName = "Group3"
              },
            };
    
            /// <summary>
            /// 登录验证
            /// </summary>
            [HubMethodName("login")]
            public async Task Login(string username, string password)
            {
                string connid = Context.ConnectionId;
                ResultModel result = new ResultModel
                {
                    Status = 0,
                    Message = "登录成功!"
                };
                if (!OnlineUser.Exists(u => u.ID == connid))
                {
                    var model = _dbuser.Find(u => u.UserName == username && u.Password == password);
                    if (model != null)
                    {
                        model.ID = connid;
                        OnlineUser.Add(model);
                        //给当前的连接分组
                        await Groups.Add(connid, model.GroupName);
                    }
                    else
                    {
                        result.Status = 1;
                        result.Message = "账号或密码错误!";
                    }
                }
                //给当前连接返回消息
                await Clients.Client(connid).LoginResponse(result);
            }
    
            /// <summary>
            /// 获取所在组的在线用户
            /// </summary>
            [HubMethodName("getUsers")]
            public async Task GetUsers()
            {
                var model = OnlineUser.Find(u => u.ID == Context.ConnectionId);
                ResultModel result = new ResultModel();
                if (model == null)
                {
                    result.Status = 1;
                    result.Message = "请先登录!";
                }
                else
                {
                    result.Status = 0;
                    result.OnlineUser = OnlineUser.FindAll(u => u.GroupName == model.GroupName);
                }
                //给所在组返回消息
                await Clients.Group(model.GroupName).GetUsersResponse(result);
            }
    
            /// <summary>
            /// 推送消息
            /// </summary>
            [HubMethodName("sendMessage")]
            public async Task SendMessage(string user, string message)
            {
                ResultModel result = new ResultModel();
                var model = OnlineUser.Find(u => u.ID == Context.ConnectionId);
                if (model == null)
                {
                    result.Status = 1;
                    result.Message = "请先登录!";
                }
                else
                {
                    result.Status = 0;
                    result.Message = $"“{user}”发送的消息:{message}";
                }
                await Clients.Group(model.GroupName).SendMessageResponse(result);
            }
    
            /// <summary>
            /// 当连接成功时的处理
            /// </summary>
            public override Task OnConnected()
            {
                return base.OnConnected();
            }
    
            /// <summary>
            /// 当连接断开时的处理
            /// </summary>
            public override Task OnDisconnected(bool stopCalled)
            {
                string connid = Context.ConnectionId;
                var model = OnlineUser.Find(u => u.ID == connid);
                int count = OnlineUser.RemoveAll(u => u.ID == connid);
                if (model != null)
                {
                    ResultModel result = new ResultModel()
                    {
                        Status = 0,
                        OnlineUser = OnlineUser.FindAll(u => u.GroupName == model.GroupName)
                    };
                    Clients.Group(model.GroupName).GetUsersResponse(result);
                }
                return base.OnDisconnected(stopCalled);
            }
        }
    
        public class UserModel
        {
            [JsonProperty("id")]
            public string ID { get; set; }
    
            [JsonProperty("userName")]
            public string UserName { get; set; }
    
            [JsonProperty("password")]
            public string Password { get; set; }
    
            [JsonProperty("groupName")]
            public string GroupName { get; set; }
        }
    
        public class ResultModel
        {
            [JsonProperty("status")]
            public int Status { get; set; }
    
            [JsonProperty("message")]
            public string Message { get; set; }
    
            [JsonProperty("onlineUser")]
            public List<UserModel> OnlineUser { get; set; }
        }
    }

    7. 运行服务端,记住地址,配置到下面步骤的客户端中

    二、创建客户端

    1. 在vs中创建一个空的“web应用程序”,命名为“SignalRClient”

    2. 把服务端的Scripts文件夹剪切过来

    3. 新建HTML页,命名为“index.html”,代码如下:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title>client - demo</title>
    </head>
    <body>
        <div>
            <div>
                <input id="txtUserName" type="text" placeholder="账号" />
                <input id="txtPasswod" type="password" placeholder="密码" /> <input id="btnLogin" type="button" value="登录" />
                <br />
                <br />
                <input id="txtMessage" type="text" placeholder="消息" /> <input id="btnSend" type="button" value="发送" />
            </div>
            <ul id="usersList">
            </ul>
            <ul id="messagesList">
            </ul>
        </div>
    
        <script src="Scripts/jquery-1.6.4.min.js"></script>
        <script src="Scripts/jquery.signalR-2.4.2.min.js"></script>
        <script type="text/javascript">
            $(function () {
                var connection = $.hubConnection("http://localhost:52157/signalr", { useDefaultPath: false }); //注意修改为你的服务端地址
                var contosoChatHubProxy = connection.createHubProxy('demoChatHub');
                connection.start()
                    .done(function () { console.log('Now connected, connection ID=' + connection.id); })
                    .fail(function () { console.log('Could not connect'); });
    
                //-----登录-----
                document.getElementById("btnLogin").addEventListener("click", function (event) {
                    var username = $("#txtUserName").val();
                    var password = $("#txtPasswod").val();
                    contosoChatHubProxy.invoke('login', username, password).done(function () {
                        console.log('Invocation of login succeeded');
                    }).fail(function (error) {
                        console.log('Invocation of login failed. Error: ' + error);
                    });
                    event.preventDefault();
                });
                contosoChatHubProxy.on('LoginResponse', function (res) {
                    if (res && res.status == 0) {
                        alert(res.message);
                        getUsers(contosoChatHubProxy);
                    } else {
                        alert('登录失败!');
                    }
                });
                //-----登录-----
    
                //-----消息-----
                document.getElementById("btnSend").addEventListener("click", function (event) {
                    var username = $("#txtUserName").val();
                    var message = $("#txtMessage").val();
                    contosoChatHubProxy.invoke('sendMessage', username, message).done(function () {
                        console.log('Invocation of sendMessage succeeded');
                    }).fail(function (error) {
                        console.log('Invocation of sendMessage failed. Error: ' + error);
                    });
                    event.preventDefault();
                });
                contosoChatHubProxy.on('SendMessageResponse', function (res) {
                    if (res && res.status == 0) {
                        var li = document.createElement("li");
                        li.textContent = res.message;
                        document.getElementById("messagesList").appendChild(li);
                    } else {
                        alert(res.message);
                    }
                });
                //-----消息-----
    
                //获取在线用户
                function getUsers(contosoChatHubProxy) {
                    contosoChatHubProxy.invoke('getUsers').done(function () {
                        console.log('Invocation of getUsers succeeded');
                    }).fail(function (error) {
                        console.log('Invocation of getUsers failed. Error: ' + error);
                    });
                    contosoChatHubProxy.on('GetUsersResponse', function (res) {
                        if (res && res.status == 0) {
                            var _html = '<li>在线用户:</li>';
                            for (var i = 0; i < res.onlineUser.length; i++) {
                                _html += `<li>${res.onlineUser[i].userName}</li>`;
                            }
                            document.getElementById("usersList").innerHTML = _html;
                        }
                    });
                }
            });
        </script>
    </body>
    </html>

    4. 右键“在浏览器中查看”,交互效果如下:

     (test1和test4是一组的,注意它们的变化;test5的组只有它一个,所以它收不到其它用户的消息)

    本文代码:https://files.cnblogs.com/files/shousiji/SignalRDemo_net4.rar

  • 相关阅读:
    进程二
    高德地图api的使用
    《架构即未来》读后感3
    三周总结
    性能战术:
    二周总结
    《 架构即未来》读后感2
    一周总结
    《架构即未来》读后感
    学生信息系统dao层
  • 原文地址:https://www.cnblogs.com/shousiji/p/15124564.html
Copyright © 2011-2022 走看看