zoukankan      html  css  js  c++  java
  • Asp.Net下SignalR的三种实现方式

    第一种:采用集线器类(Hub)+非自动生成代理模式:

                  服务端与客户端分别定义的相对应的方法,客户端通过代理对象调用服务端的方法,服务端通过IHubConnectionContext回调客户端的方法,客户端通过回调方法接收结果。

    服务端代码:

    //StartUp.cs  采用OWIN启动方式
    using System;
    
    using System.Threading.Tasks;
    
    using Microsoft.Owin;
    
    using Owin;
    
    using Microsoft.AspNet.SignalR;
    
     
    
    [assembly: OwinStartup(typeof(TestWebApp.Models.Startup))]
    
     
    
    namespace TestWebApp.Models
    
    {
    
        public class Startup
    
        {
    
            public void Configuration(IAppBuilder app)
    
            {
    
                app.MapSignalR();
    
            }
    
        }
    
    }
    
     
    
     
    
    //ChatHub类文件
    
     
    
    using Microsoft.AspNet.SignalR;
    
    using Microsoft.AspNet.SignalR.Hubs;
    
    using System;
    
    using System.Collections.Concurrent;
    
    using System.Collections.Generic;
    
    using System.Linq;
    
    using System.Web;
    namespace TestWebApp.Models
    {
        [HubName("chat")]
        public class ChatHub : Hub
        {
            public static ConcurrentDictionary<string, string> OnLineUsers = new ConcurrentDictionary<string, string>();
    
            [HubMethodName("send")]
            public void Send(string message)
    
            {
                string clientName = OnLineUsers[Context.ConnectionId];
    
                message = HttpUtility.HtmlEncode(message).Replace("
    ", "<br/>").Replace("
    ", "<br/>");
    
                Clients.All.receiveMessage(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), clientName, message);
            }
    
            [HubMethodName("sendOne")]
            public void Send(string toUserId, string message)
            {
                string clientName = OnLineUsers[Context.ConnectionId];
    
                message = HttpUtility.HtmlEncode(message).Replace("
    ", "<br/>").Replace("
    ", "<br/>");
    
                Clients.Caller.receiveMessage(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), string.Format("您对 {1}", clientName, OnLineUsers[toUserId]), message);
    
                Clients.Client(toUserId).receiveMessage(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), string.Format("{0} 对您", clientName), message);
            }
    
            public override System.Threading.Tasks.Task OnConnected()
            {
                string clientName = Context.QueryString["clientName"].ToString();
    
                OnLineUsers.AddOrUpdate(Context.ConnectionId, clientName, (key, value) => clientName);
    
                Clients.All.userChange(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), string.Format("{0} 加入了。", clientName), OnLineUsers.ToArray());
    
                return base.OnConnected();
            }
    public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled) { string clientName = Context.QueryString["clientName"].ToString(); Clients.All.userChange(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), string.Format("{0} 离开了。", clientName), OnLineUsers.ToArray()); OnLineUsers.TryRemove(Context.ConnectionId, out clientName); return base.OnDisconnected(stopCalled); } } }

    web端代码:

    <!DOCTYPE html>
    <html>
    <head>
    
        <meta name="viewport" content="width=device-width" />
    
        <meta charset="utf-8" />
    
        <title>聊天室</title>
    
        <script src="~/Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
    
        <script src="~/Scripts/jquery.signalR-2.2.0.min.js" type="text/javascript"></script>
    
        <style type="text/css">
    
            #chatbox {
    
                width: 100%;
    
                height: 500px;
    
                border: 2px solid blue;
    
                padding: 5px;
    
                margin: 5px 0px;
    
                overflow-x: hidden;
    
                overflow-y: auto;
    
            }
    
            .linfo {
    
            }
    
            .rinfo {
    
                text-align: right;
    
            }
    
        </style>
    
        <script type="text/javascript">
    
            $(function () {
                var clientName = $("#clientname").val();
    
                var eChatBox = $("#chatbox");
    
                var eUsers = $("#users");
                var conn = $.hubConnection();
    
                conn.qs = { "clientName": clientName };
    
                conn.start().done(function () {
    
                    $("#btnSend").click(function () {
    
                        var toUserId = eUsers.val();
    
                        if (toUserId != "") {
    
                            chat.invoke("sendOne", toUserId, $("#message").val())
    
                            .done(function () {
    
                                //alert("发送成功!");
    
                                $("#message").val("").focus();
    
                            })
    
                            .fail(function (e) {
    
                                alert(e);
    
                                $("#message").focus();
    
                            });
    
                        }
    
                        else {
    
                            chat.invoke("send", $("#message").val())
    
                            .done(function () {
    
                                //alert("发送成功!");
    
                                $("#message").val("").focus();
    
                            })
    
                            .fail(function (e) {
    
                                alert(e);
    
                                $("#message").focus();
    
                            });
    
                        }
    
                    });
                });
    
                var chat = conn.createHubProxy("chat");
    
                chat.on("receiveMessage", function (dt, cn, msg) {
    
                    var clsName = "linfo";
    
                    if (cn == clientName || cn.indexOf("您对") >= 0) clsName = "rinfo";
    
                    eChatBox.append("<p class='" + clsName + "'>" + dt + " <strong>" + cn + "</strong> 说:<br/>" + msg + "</p>");
    
                    eChatBox.scrollTop(eChatBox[0].scrollHeight);
    
                });
    chat.on(
    "userChange", function (dt, msg, users) { eChatBox.append("<p>" + dt + " " + msg + "</p>"); eUsers.find("option[value!='']").remove(); for (var i = 0; i < users.length; i++) { if (users[i].Value == clientName) continue; eUsers.append("<option value='" + users[i].Key + "'>" + users[i].Value + "</option>") } }); }); </script> </head> <body> <h3>大众聊天室</h3> <div id="chatbox"> </div> <div> <span>聊天名称:</span> @Html.TextBox("clientname", ViewBag.ClientName as string, new { @readonly = "readonly", style = "300px;" }) <span>聊天对象:</span> @Html.DropDownList("users", ViewBag.OnLineUsers as IEnumerable<SelectListItem>) </div> <div> @Html.TextArea("message", new { rows = 5, style = "500px;" }) <input type="button" value="发送消息" id="btnSend" /> </div> </body> </html>

    备注:服务端与客户端代码都比较简单,网上相关的说明也有,这里就不再解说了,只说一下这种方式JS端调用服务端方法采用:chat.invoke,而被服务端回调的方法则采用:chat.on (这里的chat是createHubProxy创建得来的)

    第二种:采用集线器类(Hub)+自动生成代理模式

    服务端代码:与第一种相同,无需改变。

    web端代码:

    <!DOCTYPE html>
    
    <html>
    
    <head>
    
        <meta name="viewport" content="width=device-width" />
    
        <meta charset="utf-8" />
    
        <title>聊天室</title>
    
        <script src="~/Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
    
        <script src="~/Scripts/jquery.signalR-2.2.0.min.js" type="text/javascript"></script>
    
        <script src="~/signalr/hubs" type="text/javascript"></script>
    
        <style type="text/css">
    
            #chatbox {
    
                width: 100%;
    
                height: 500px;
    
                border: 2px solid blue;
    
                padding: 5px;
    
                margin: 5px 0px;
    
                overflow-x: hidden;
    
                overflow-y: auto;
    
            }
    
            .linfo {
    
            }
    
    
            .rinfo {
    
                text-align: right;
    
            }
    
        </style>
    
        <script type="text/javascript">
    
            $(function () {
    
                var clientName = $("#clientname").val();
    
                var eChatBox = $("#chatbox");
    
                var eUsers = $("#users");
    
                var chat = $.connection.chat;
    
                $.connection.hub.qs = { "clientName": clientName };
    
                chat.state.test = "test";
    
                chat.client.receiveMessage = function (dt, cn, msg) {
    
                    var clsName = "linfo";
    
                    if (cn == clientName || cn.indexOf("您对")>=0) clsName = "rinfo";
    
                    eChatBox.append("<p class='" + clsName + "'>" + dt + " <strong>" + cn + "</strong> 说:<br/>" + msg + "</p>");
    
                    eChatBox.scrollTop(eChatBox[0].scrollHeight);
    
                }
    
                chat.client.userChange = function (dt, msg, users) {
    
                    eChatBox.append("<p>" + dt + " " + msg + "</p>");
    
                    eUsers.find("option[value!='']").remove();
    
                    for (var i = 0; i < users.length; i++) {
    
                        if (users[i].Value == clientName) continue;
    
                        eUsers.append("<option value='" + users[i].Key + "'>" + users[i].Value + "</option>")
    
                    }
    
                }
    
                $.connection.hub.start().done(function () {
    
                    $("#btnSend").click(function () {
    
                        var toUserId = eUsers.val();
    
                        if (toUserId != "") {
    
                            chat.server.sendOne(toUserId, $("#message").val())
    
                                .done(function () {
    
                                    //alert("发送成功!");
    
                                    $("#message").val("").focus();
    
                                })
    
                                .fail(function (e) {
    
                                    alert(e);
    
                                    $("#message").focus();
    
                                });
    
                        }
    
                        else {
    
                            chat.server.send($("#message").val())
    
                            .done(function () {
    
                                //alert("发送成功!");
    
                                $("#message").val("").focus();
    
                            })
    
                            .fail(function (e) {
    
                                alert(e);
    
                                $("#message").focus();
    
                            });
    
                        }
    
                    });
    
                });
    
            });
    
        </script>
    
    </head>
    
    <body>
    
        <h3>大众聊天室</h3>
    
        <div id="chatbox">
    
        </div>
    
        <div>
    
            <span>聊天名称:</span>
    
            @Html.TextBox("clientname", ViewBag.ClientName as string, new { @readonly = "readonly", style = "300px;" })
    
            <span>聊天对象:</span>
    
            @Html.DropDownList("users", ViewBag.OnLineUsers as IEnumerable<SelectListItem>)
    
        </div>
    
        <div>
    
            @Html.TextArea("message", new { rows = 5, style = "500px;" })
    
            <input type="button" value="发送消息" id="btnSend" />
    
        </div>
    
    </body>
    
    </html>

    备注:特别需要注意的是,需要引用一个“不存在的JS目录”:<script src="~/signalr/hubs" type="text/javascript"></script>,为什么要打引号,是因为我们在写代码的时候是不存在的,而当运行后就会自动生成signalr的代理脚本,这就是与非自动生成代理脚本最根本的区别,也正是因为这个自动生成的脚本,我们可以在JS中更加方便的调用服务端方法及定义回调方法,调用服务端方法采用:chat.server.XXX,而被服务端回调的客户端方法则采用:chat.client.XXX。

    第三种:采用持久化连接类(PersistentConnection)

    服务端代码:

    //Startup类:
    
    using System;
    
    using System.Threading.Tasks;
    
    using Microsoft.Owin;
    
    using Owin;
    
    using Microsoft.AspNet.SignalR;
    
    [assembly: OwinStartup(typeof(TestWebApp.Models.Startup))]
    
    namespace TestWebApp.Models
    
    {
    
        public class Startup
    
        {
    
            public void Configuration(IAppBuilder app)
    
            {
    
                app.MapSignalR<MyConnection>("/MyConnection");
    
            }
    
        }
    
    }
     
    
    //MyConnection类:
    
    using System;
    
    using System.Collections.Generic;
    
    using System.Linq;
    
    using System.Threading.Tasks;
    
    using System.Web;
    
    using Microsoft.AspNet.SignalR;
    
     
    namespace TestWebApp.Models
    
    {
    
        public class MyConnection : PersistentConnection
    
        {
    
            private static List<string> monitoringIdList = new List<string>();
    
            protected override Task OnConnected(IRequest request, string connectionId)
    
            {
    
                bool IsMonitoring = (request.QueryString["Monitoring"] ?? "").ToString() == "Y";
    
                if (IsMonitoring)
    
                {
    
                    if (!monitoringIdList.Contains(connectionId))
    
                    {
    
                        monitoringIdList.Add(connectionId);
    
                    }
    
                    return Connection.Send(connectionId, "ready");
    
                }
    
                else
    
                {
    
                    if (monitoringIdList.Count > 0)
    
                    {
    
                        return Connection.Send(monitoringIdList, "in_" + connectionId);
    
                    }
    
                    else
    
                    {
    
                        return Connection.Send(connectionId, "nobody");
    
                    }
    
                }
    
            }
    
    
            protected override Task OnReceived(IRequest request, string connectionId, string data)
    
            {
    
                if (monitoringIdList.Contains(connectionId))
    
                {
    
                    return Connection.Send(data, "pass");
    
                }
    
                return null;
    
            }
    
    
            protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
    
            {
    
                if (!monitoringIdList.Contains(connectionId))
    
                {
    
                    return Connection.Send(monitoringIdList, "out_" + connectionId);
    
                }
    
                return null;
    
            }
    
        }
    
    }

    web端代码:

    <!DOCTYPE html>
    
     
    
    <html>
    
    <head>
    
        <meta name="viewport" content="width=device-width" />
    
        <title>MonitoringPage</title>
    
        <script src="~/Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
    
        <script src="~/Scripts/jquery.signalR-2.2.0.min.js" type="text/javascript"></script>
    
        <style type="text/css">
    
            table {
    
                border:1px solid #808080;
    
                width:600px;
    
            }
    
            td {
    
                border:1px solid #808080;
    
                padding:3px;
    
            }
    
            .odd{ background-color: #bbf;}
    
            .even{ background-color:#ffc; }
    
            .non-temptr {
    
                display:none;
    
            }
    
        </style>
    
        <script type="text/javascript">
    
            $(function () {
    
                $("#userstable tbody tr:odd").addClass("odd");
    
                $("#userstable tbody tr:even").addClass("even");
    
     
    
                var conn = $.connection("/MyConnection", {"Monitoring":"Y"});
    
     
    
                conn.start().done(function () {
    
                    $("#userstable").delegate("button.pass", "click", function () {
    
                        var rid = $(this).parent("td").prev().attr("data-rid");
    
                        conn.send(rid);
    
                        var tr = $(this).parents("tr");
    
                        tr.remove();
    
                    });
    
                    
    
                }).fail(function (msg) {
    
                    alert(msg);
    
                });
    
     
    
                conn.received(function (msg) {
    
                    if (msg == "ready")
    
                    {
    
                        $("#spstatus").html("监控服务已就绪");
    
                        return;
    
                    }
    
                    else if (msg.indexOf("in_") == 0) {
    
                        var tr = $(".non-temptr").clone(true);
    
                        tr.removeClass("non-temptr");
    
                        var td = tr.children().first();
    
                        var rid = msg.toString().substr("in_".length);
    
                        td.html(rid + "进入被监控页面,是否允许?");
    
                        td.attr("data-rid", rid);
    
                        $("#userstable tbody").append(tr);
    
                    }
    
                    else
    
                    {
    
                        var rid = msg.toString().substr("out_".length);
    
                        $("td[data-rid=" + rid + "]").parent("tr").remove();
    
                    }
    
                });
    
     
    
            });
    
        </script>
    
    </head>
    
    <body>
    
        <div>
    
            以下是实时监控到进入EnterPage页面的用户情况:(服务状况:<strong><span id="spstatus"></span></strong>)
    
        </div>
    
        <table id="userstable">
    
            <tr>
    
                <td>用户进入消息</td>
    
                <td>授 权</td>
    
            </tr>
    
            <tr class="non-temptr">
    
                <td></td>
    
                <td style="100px"><button class="pass">允许</button></td>
    
            </tr>
    
        </table>
    
    </body>
    
    </html>
    
     
    
     
    
    <!-- EnterPage.cshtml 监控受限页面-->
    
    <!DOCTYPE html>
    
     
    
    <html>
    
    <head>
    
        <meta name="viewport" content="width=device-width" />
    
        <title>EnterPage</title>
    
        <script src="~/Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
    
        <script src="~/Scripts/jquery.signalR-2.2.0.min.js" type="text/javascript"></script>
    
    </head>
    
    <body>
    
        <script type="text/javascript">
    
            $(function () {
    
                var conn = $.connection("/MyConnection");
    
     
    
                conn.start().fail(function (msg) {
    
                    alert(msg);
    
                });
    
     
    
                conn.received(function (data) {
    
                    if (data == "pass") {
    
                        $("#msg").html("管理员已审核通过,可以进入浏览详情。");
    
                        setTimeout(function () {
    
                            self.location = "http://www.zuowenjun.cn";
    
                        }, 3000);
    
                    }
    
                    else
    
                    {
    
                        $("#msg").html("无管理员在线,请稍候再重新进入该页面。");
    
                    }
    
                });
    
            });
    
        </script>
    
        <div id="msg"> 
    
            该页面浏览受限,已自动将您的浏览请求发给管理员,请稍候。。。
    
        </div>
    
    </body>
    
    </html>

    备注:上述代码可以看出与采用Hub(集线器类)的不同之处,一是:Startup.Configuration中是需要指定app.MapSignalR<MyConnection>("/MyConnection"),二是需实现继承自PersistentConnection类的自定义的持久化连接类,在这个连接中可以重写:OnConnected、OnDisconnected、OnReceived、OnReconnected、ProcessRequest方法,同时有几个重要的属性成员Connection、Groups,服务端发消息给客户端采用:Connection.Broadcast(广播,所有客户端都可以收到消息),Connection.Send(发送给指定的客户端)

  • 相关阅读:
    LeetCode:Remove Nth Node From End of List
    链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)
    快速排序partition过程常见的两种写法+快速排序非递归实现
    LeetCode:Permutations, Permutations II(求全排列)
    LeetCode:3Sum, 3Sum Closest, 4Sum
    LeetCode:Two Sum
    判断一个图是否有环
    c++设计一个无法被继承的类
    设计模式--单例模式
    windows多线程同步互斥--总结
  • 原文地址:https://www.cnblogs.com/xtxk110/p/12896208.html
Copyright © 2011-2022 走看看