ASP.NET 即时通讯之SignalR

最近比较累,也没时间写博客,今天索性来一篇,很多时候,网站即时通讯,推送必不可少。但是这部分大家都觉得是那么陌生,不敢尝试,今天我就给大家讲讲SignalR的简单使用。

首先我们打开VS,创建一个web应用程序。然后Nuget安装SignalR,如下。

安装好之后,我们在项目的引用中发现程序给我们自动引用了相关的dll以及js文件。

接着我们创建两个类,一个是ChatHub,继承自Hub,如下

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

namespace Chart.SignalR
{
    [HubName("ChatRoomHub")]
    public class ChatHub : Hub
    {
        static List<UserEntity> users = new List<UserEntity>();
        public async Task UserEnter(string nickName)
        {
            UserEntity userEntity = new UserEntity
            {
                NickName = nickName,
                ConnectionId = Context.ConnectionId
            };

            users.Add(userEntity);
            await Clients.All.NotifyUserEnter(nickName, users);
        }

        public async Task SendMessage(string nickName, string message)
        {
            await Clients.All.NotifySendMessage(nickName, message);
        }

        public override Task OnDisconnected(bool isStop)
        {
            var currentUser = users.FirstOrDefault(u => u.ConnectionId == Context.ConnectionId);
            if (currentUser != null)
            {
                users.Remove(currentUser);
                Clients.Others.NotifyUserLeft(currentUser.NickName, users);
            }
            return base.OnDisconnected(isStop);
        }
    }

    public class UserEntity
    {
        public string NickName { get; set; }

        public string ConnectionId { get; set; }
    }
}

在这里我们给ChatHub起了别名ChatRoomHub。大家从代码上看就知道我写的将是一个聊天室的代码。这里users用来存储在线人员,NickName存放用户进聊天室之前输入的昵称,ConnectionId则是Hub上下文给每个连接分配的唯一标识,这样方便我们判断用户离线的情况。

在这个Hub子类中,

UserEnter方法用来记录加入聊天的用户,并通知到其他客户端浏览器更新UI。

SendMessage方法用来将客户端发送的消息推送到所有的客户端浏览器。

OnDisconnected顾名思义就是客户端离线,离线后将离线用户从用户数组中删除掉,并通知其他用户浏览器更新UI,注意这里的Clients.Others

接着我们再看一下StartUp类

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(Chart.SignalR.StartUp))]
namespace Chart.SignalR
{
    public class StartUp
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

这里OwinStartup标识了哪个类是自动启动,app.MapSignalR()则是将app builder 管道映射到一个路径上,待会我们会看到这个路径。

OK,接下来我们看下客户端的代码

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link rel="stylesheet" href="StyleSheet/bootstrap/css/bootstrap.min.css" />
    <script src="Scripts/jquery-1.6.4.min.js"></script>
    <script src="Scripts/jquery.signalR-2.2.0.min.js"></script>
    <script src="Scripts/bootstrap.min.js"></script>
    <script src="signalr/hubs"></script>
    <style type="text/css">
        .demo {
            margin-bottom: 20px;
            padding-left: 50px;
            position: relative;
        }

        .triangle {
            position: absolute;
            top: 50%;
            margin-top: -8px;
            left: 42px;
            display: inline;
            width: 0;
            height: 0;
            overflow: hidden;
            line-height: 0;
            font-size: 0;
            border-bottom: 8px solid #FFF;
            border-top: 8px solid #FFF;
            border-left: none;
            border-right: 8px solid #3079ED;
        }

        .demo .article {
            float: left;
            color: #FFF;
            display: inline;
            zoom: 1;
            padding: 5px 10px;
            border: 1px solid #3079ED;
            background: #eee;
            border-radius: 5px;
            background-color: #4D90FE;
            background-image: -webkit-gradient(linear,left top,left bottom,from(#4D90FE),to(#4787ED));
            background-image: -webkit-linear-gradient(top,#4D90FE,#4787ED);
            background-image: -moz-linear-gradient(center top, #4D90FE, #4787ED);
            background-image: linear-gradient(top,#4D90FE,#4787ED);
        }

        .fr {
            padding-left: 0px;
            padding-right: 50px;
        }

            .fr .triangle {
                left: auto;
                right: 42px;
                border-bottom: 8px solid #FFF;
                border-top: 8px solid #FFF;
                border-right: none;
                border-left: 8px solid #3079ED;
            }

            .fr .article {
                float: right;
            }

        .round-img-list {
            border-radius: 50%;
            border: solid;
            border-width: 1px;
            border-color: #FFCC00;
            width: 45px;
            height: 45px;
        }

        .clear-float {
            clear: both;
        }
    </style>
</head>
<body>
    <div class="container" style="margin-top: 10px">
        <div class="row">
            <div class="col-md-9">
                <div class="panel panel-primary">
                    <div class="panel-heading">
                        聊天室
                    </div>
                    <div id="div_msgbody" class="panel-body" style=‘min-height: 500px; max-height: 500px; overflow: auto; max-width: 850px;‘>
                        <div id="div_msg" style=‘word-wrap: break-word; word-break: break-word;‘></div>
                    </div>
                    <div class="panel-footer">
                        <div class="row">
                            <div class="col-md-11">
                                <div class="input-group">
                                    <span class="input-group-addon">内容:</span>
                                    <input id="message" type="text" class="form-control" maxlength="500" placeholder=‘在此输入聊天内容‘ />
                                </div>
                            </div>
                            <div class="col-md-1">
                                <button id="btn_Send" type="button" class="btn btn-info">发送</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-md-3">
                <div class="panel panel-primary">
                    <div class="panel-heading">
                        用户列表
                    </div>
                    <div class="panel-body" style=‘min-height: 500px; max-height: 500px; overflow: auto;‘>
                        <div id="div_member"></div>
                    </div>
                    <div class="panel-footer">
                        <div style="height: 34px; height: 34px; line-height: 34px">
                            人员总数:<label id="lab_total">0</label>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <script type="text/javascript">
        var userNickName;
        jQuery(document).ready(function () {
            while (!userNickName) {
                userNickName = window.prompt("请输入昵称!");
            }

            var chatHub = $.connection.ChatRoomHub;

            chatHub.client.NotifyUserEnter = function (nickName, users) {
                buildUserTemplate(users);
            }

            chatHub.client.NotifyUserLeft = function (nickName, users) {
                buildUserTemplate(users);
            }

            chatHub.client.NotifySendMessage = function (nickName, message) {
                var userAvatar = ‘http://www.wed114.cn/jiehun/uploads/allimg/160426/39_160426110624_1.jpg‘;
                if (nickName == userNickName) {
                    $("#div_msg").append("<div style=‘text-align:right;float:right‘>"
                    + "<span style=‘margin-right:10px‘>" + nickName + "</span>"
                     + "<img src=‘" + userAvatar + "‘ style=‘height:40px;width:40px;position:relative‘/>"
                    + "<div class=‘demo clearfix fr‘>"
                    + "<span class=‘triangle‘></span>"
                    + "<div class=‘article‘ style=‘word‘>" + message
                    + "</div></div></div><div class=‘clear-float‘/>");
                }
                else {
                    $("#div_msg").append("<div>"
                     + "<img src=‘" + userAvatar + "‘ style=‘height:40px;width:40px;position:relative‘/>"
                     + "<span style=‘left:10px;position:relative‘>" + nickName + "</span>"
                     + "<div class=‘demo clearfix‘>"
                     + "<span class=‘triangle‘></span>"
                     + "<div class=‘article‘>" + message
                     + "</div></div></div>");
                }

                var objDiv = document.getElementById("div_msgbody");
                objDiv.scrollTop = objDiv.scrollHeight;
            }

            $.connection.hub.start().done(function () {
                chatHub.server.userEnter(userNickName);
            });

            $("#message").keydown(function (event) {
                if (event.keyCode == 13) {
                    if ($("#message").val() != "") {
                        chatHub.server.sendMessage(userNickName, $("#message").val());
                        $("#message").val("");
                    }
                }
            });

            $("#btn_Send").click(function () {
                if ($("#message").text != "") {
                    chatHub.server.sendMessage(userNickName, $("#message").val());
                    $("#message").val("");
                }
            })

            function buildUserTemplate(users) {
                $("#lab_total").text(users.length);
                var userTemplate = "<ul style=‘list-style:none;‘>"
                $.each(users, function (e, v) {
                    var userAvatar = ‘http://www.wed114.cn/jiehun/uploads/allimg/160426/39_160426110624_1.jpg‘;
                    userTemplate += "<li style=‘padding-top:5px;‘>"
                        + "<img class=‘round-img-list‘ src=‘" + userAvatar + "‘/>"
                        + "<label style=‘color:#666666;margin-left:10px‘>" + v.NickName + "</label>"
                        + "</li>";
                });

                userTemplate += "</ul>";

                $("#div_member").html(userTemplate);
            }
        });
    </script>
</body>
</html>

布局我就不说了,BootStrap布局。这里需要注意这个路径

<script src="signalr/hubs"></script>

这个路径就是上面说的管道map的路径,在这个路径下会生成hubs.js文件,在这个文件中有注册hub代码,生成hub代理等方法。

然后在js中,先让用户输入昵称,输入后,得到chatHub对象,然后

实现NotifyUserEnter,NotifyUserLeft以及NotifySendMessage方法。NotifyUserEnter和NotifyUserLeft方法主要是更新右边panel显示的人员信息。而NotifySendMessage方法则是将服务器推送出的聊天信息展示在span中。在这里我们为了区分自己和别人,自己的聊天信息显示在右边,别人的显示在左边。

var objDiv = document.getElementById("div_msgbody");
objDiv.scrollTop = objDiv.scrollHeight;

这句的意思是如果聊天记录太多出现了滚动条,则将滚动条自动滚动到最底部。

$.connection.hub.start().done(function () {        
     chatHub.server.userEnter(userNickName);
});

这句意思是当有新用户时,就会和服务端建立连接,连接完成后,调用Server端的UserEnter方法,在客户端这里写小写开头,记住。最后发送消息,调用server端的SendMessage方法。

OK,至此程序大概就讲完了,很简单的一个demo,大家看了的也评价评价。俗话说无图无真相,看图

好了今天就到这里,后面我会继续写nodejs相关的博客。

时间: 2024-10-20 23:01:40

ASP.NET 即时通讯之SignalR的相关文章

MVC中使用SignalR打造酷炫实用的即时通讯功能

資料來源:http://www.fangsi.net/1144.html 前言,现在这世道写篇帖子没个前言真不好意思发出来.本贴的主要内容来自于本人在之前项目中所开发的一个小功能,用于OA中的即时通讯.由于当时走的太急,忘记把代码拿出来.想想这已经是大半年前的事情了,时间过了这么久,在当时最新的SignalR2.0.1到现在已经变成了2.2.昨天晚上特地熬了个夜,重新又把它写出来做了一个小小的Demo.当然我只是大自然的搬运工,这个SignalR即时通讯功能里面有一些前端的类库不是我自己写的.我

MVC中使用SignalR打造酷炫实用的即时通讯功能附源码

前言,现在这世道写篇帖子没个前言真不好意思发出来.本贴的主要内容来自于本人在之前项目中所开发的一个小功能,用于OA中的即时通讯.由于当时走的太急,忘记把代码拿出来.想想这已经是大半年前的事情了,时间过了这么久,在当时最新的SignalR2.0.1到现在已经变成了2.2.昨天晚上特地熬了个夜,重新又把它写出来做了一个小小的Demo.当然我只是大自然的搬运工,这个SignalR即时通讯功能里面有一些前端的类库不是我自己写的.我只是改吧改吧~~在此鸣谢 @贤心,是他的几条库才使得我的这个功能如此酷炫.

基于SignalR的web端即时通讯 - ChatJS

先上图. ChatJS 是基于SignalR实现的Web端IM,界面风格模仿的是“脸书”,可以很方便的集成到已有的产品中. 项目官网:http://chatjs.net/ github地址:https://github.com/andrerpena/ChatJS 在浏览器端,ChatJS是一系列的jQuery插件,这些代码都是使用TypeScript(微软开发的JS的一个面向对象超集,可以编译成JS)编写.在服务端,是一个简单的类库.如果要集成ChatJS ,服务端需要做的仅仅是实现 IChat

SignalR实现即时通讯技术,支持跨域

一.SignalR环境要求 1.需要有 .NET Framework 4.5,服务器端需要 Windows Server 2008 R2 以上的操作系统以及 IIS7 二.实现机制 SignalR 的实现机制与 .NET WCF 或 Remoting 是相似的,都是使用远程代理来实现.在具体使用上,有两种不同目的的接口:PersistentConnection 和 Hubs,其中 PersistentConnection 是实现了长时间的 JavaScript 轮询(类似于 Comet),Hub

[Asp.net 开发系列之SignalR篇]专题六:使用SignalR实现消息提醒

一.引言 前面一篇文章我介绍了如何使用SignalR实现图片的传输,然后对于即时通讯应用来说,消息提醒是必不可少的.现在很多网站的都有新消息的提醒功能.自然对于SignalR系列也少不了这个功能的实现了.在这篇文章中将介绍如何使用SignalR+iNotify库来实现新消息的声音和弹框提醒. 二.消息提醒的实现思路 消息提醒也就是当客户有新消息来时,在客户端的右下角进行弹框提醒.要实现这个功能的思路是: SignalR服务端推送消息到客户端的实现方式为调用客户端的receiveMessage方法

在ASP.NET 5中使用SignalR

(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:SignalR作为ASP.NET中进行Web实时双向通信的组件,在ASP.NET 5中也得到了同步发展.不过,用法和之前还是在细节上有所不同,而资料又相对稀少.本文就是一个简单的入门向导. 通过SignalR,开发人员可以在ASP.NET开发的Web应用中实现服务器和客户端的双向实时通信.服务器可以即时推送内容给在线的客户端.SignalR首选Web Sockets作为底层实现,针对非现代浏览

我的即时通讯系统发布前,先小秀一下

一.开发概要: 开发人员:本人 联系电话:18667102122 开发人数:1人 版权所有:杭州云寻觅网络科技有限公司 开发周期:2014-05-27 至今 备注:就一个人开发的,不要总是拿这个做了2,3个月的东西,跟几千人做了10多年的产品去比较,没有可比性.   所以比较的时候希望大家别失去理智! 二.架构及概述 1.总体架构图 2.服务端功能模块图 3.客户端功能模块图 4.客户端浏览器组件功能模块图 三.组成文件: 服务端:ImServer_5_0_0.exe 大小 88.6MB(含jd

java SSM框架 多数据源 代码生成器 websocket即时通讯 shiro redis 后台框架源码

获取[下载地址]   QQ: 313596790官网 http://www.fhadmin.org/A 调用摄像头拍照,自定义裁剪编辑头像,头像图片色度调节B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,快速开发利器)+快速表单构建器 freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类,service等完整模块C 集成阿里巴巴数据库连接池druid  数据库连接池  阿里巴巴的 druid.Druid在监控.可扩展性.稳定性和性能方面都

XMPP即时通讯

XMPP:XMPP是基于XML的点对点通讯协议,The Extensible Messaging and Presence Protocol(可扩展通讯和表示协议). XMPP可用于服务类实时通讯,表示和需求响应服务中的XML数据元流失传输.XMPP以Jabber协议为基础,而Jabber是即时通讯中常用的开放式协议. 基本结构. XML是一个典型的C/S架构,而不是像大多数即时通讯软件一样,使用P2P客户端到客户端的架构,也就是说在大多数情况下,当两个客户端进行通讯时,他们的消息都是通过服务器