首页 后端开发 C#.Net教程 SignalR实现实时Web聊天的实例代码

SignalR实现实时Web聊天的实例代码

May 25, 2018 pm 04:12 PM
.net asp.net mvc signalr 实时聊天

本篇文章主要介绍了Asp.net SignalR来做实时Web聊天实例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本章和大家分享的内容是使用Signal R框架创建个简易的群聊功能,主要讲解如何在.Net的MVC中使用这个框架,由于这个项目有官方文档(当然全英文),后面也不打算写分享篇了,主要目的是让朋友们在需要使用Web实时通信的时候有更多一种解决方案,毕竟这是微软主推的一种解决方案之一。

SignalR网上简介

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

SignalR当然也提供了非常简单易用的高阶API,使服务器端可以单个或批量调用客户端上的JavaScript函数,并且非常 方便地进行连接管理,例如客户端连接到服务器端,或断开连接,客户端分组,以及客户端授权,使用SignalR都非常 容易实现。

SignalR将与客户端进行实时通信带给了ASP .NET 。当然这样既好用,而且也有足够的扩展性。以前用户需要刷新页面或使用Ajax轮询才能实现的实时显示数据,现在只要使用SignalR,就可以简单实现了。最重要的是您无需重新建立项目,使用现有ASP .NET项目即可无缝使用SignalR。

群聊实例效果

咋们先来看看测试用例的效果吧,效果图:

界面及其简单,样式这里就不考虑了,主要是展示其用法,这里涉及到的功能有:

1. 统计在线人数量

2. 显示在线人数的昵称和连接方式(本测试用例支持webSockets和longPolling(长连接))

3. 群聊信息

MVC中如何使用SignalR

首先,我们平常做法创建MVC的Web项目,然后通过Nuget控制台命令: Install-package Microsoft.AspNet.SignalR 加入SignalR的依赖,自动添加的包如下:

 <package id="Microsoft.AspNet.SignalR" version="2.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.SignalR.Core" version="2.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.SignalR.JS" version="2.2.2" targetFramework="net45" />
 <package id="Microsoft.AspNet.SignalR.SystemWeb" version="2.2.2" targetFramework="net45" />
登录后复制

并且自动往MVC项目中的Script文件夹中增加相关的js文件:

jquery.signalR-2.2.2.min.js

jquery.signalR-2.2.2.js

然后,我们需要在项目一级目录创建一个文件名称为Startup.cs的类,里面主要内容补全不下:

[assembly: OwinStartup(typeof(Stage.Api.Extend.Startup))]
namespace Stage.Api.Extend
{
  public class Startup
  {
    public void Configuration(IAppBuilder app)
    {
      app.MapSignalR("/chat", new Microsoft.AspNet.SignalR.HubConfiguration
      {
        EnableDetailedErrors = true,
        EnableJavaScriptProxies = true
      });
    }
  }
}
登录后复制

首先我们从上往下分析注意点:

1. OwinStartup(Type) 构造函数传递的是一个类型,而这个类型对应的就是我们创建的Startup类,这个通过这个构造函数类标记起始位置;

2. namespace Stage.Api.Extend 是我项目的命名空间,这个可以随便定义;

3. public void Configuration(IAppBuilder app) 函数是固定必须的,这里程序会首先进入这个方法执行里面的逻辑代码;

4. app.MapSignalR 是扩展的IAppBuilder接口方法,他有多种表现形式,这里我选择的是 public <a href="http://www.php.cn/wiki/188.html" target="_blank">static</a> IAppBuilder MapSignalR(this IAppBuilder builder, <a href="http://www.php.cn/wiki/57.html" target="_blank">string</a> path, HubConfiguration configuration); ,这里看有点类似于咋们MVC的路由,这里主要注意的是这个Path参数,在前端页面的时候需要用到这个路径;

到这里后台需要的配置其实已经就完成了,下面是具体需要操作的业务逻辑处理类,新建一个类(这里我取名为ChatHub)并继承Hub(这是SignalR框架提供),然后里面的逻辑代码如下:

public class ChatHub : Hub
  {
    //
    public int Num = 10001;
    public static List<MoHubUser> _Users = new List<MoHubUser>();

    /// <summary>
    /// 添加聊天人
    /// </summary>
    /// <param name="user"></param>
    public void AddUser(MoHubUser user)
    {

      user.Id = Context.ConnectionId;
      if (!_Users.Any(b => b.Id == user.Id))
      {
        _Users.Add(user);
      }

      //Clients.All.newUser(user);
      Clients.All.userList(_Users);
    }

    /// <summary>
    /// 发送信息
    /// </summary>
    /// <param name="user"></param>
    /// <param name="message"></param>
    public void SendAll(MoHubUser user, string message)
    {
      Clients.All.addNewMessageToPage(user, message);
    }

    /// <summary>
    /// 某个聊天人退出是,通知所有在线人重新加载聊天人数
    /// </summary>
    /// <param name="stopCalled"></param>
    /// <returns></returns>
    public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
    {
      var user = _Users.SingleOrDefault(x => x.Id == Context.ConnectionId);
      if (user != null)
      {
        _Users.Remove(user);
        Clients.All.userList(_Users);
      }
      return base.OnDisconnected(stopCalled);
    }
  }
登录后复制

上面的3个方法分别做了:添加聊天人到List,发送信息到客户端,某个连接失效后通知各个有效的聊天人重新加载信息;这里值得关注的是通过重新 public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled) 方法来实现捕获并移除失效连接(这里是聊天人的信息);整篇测试用例通过Context.ConnectionId来保证连接的唯一性,只要有新的链接请求,那么服务端就会分配一个唯一串给这个链接,当客户端关闭页面或关闭链接这个是有就能在OnDisconnected方法中捕获到这个失效的链接的ConnectionId,这样就达到了移除失效聊天人的要求了;为了代码的方便性,这里创建了一个聊天人信息类:

public class MoHubUser
  {

    public string Id { get; set; }
    public string NickName { get; set; }
    public string TransportMethod { get; set; }
  }
登录后复制

到这里后台的聊天室代码就完成了就是这么简单;我们再来看试图中如何来写代码,这里我先给出我的html布局代码:

 @{
  ViewBag.Title = "神牛聊天室 - SignalR";
}
<style type="text/css">
  .p_left {
    width: 70%;
    float: left;
  }

  .p_right {
    width: 28%;
    float: left;
  }

  .ul {
    list-style: none;
    border: 1px solid #ccc;
    height: 500px;
    overflow-y: scroll;
    color: black;
  }

    .ul li {
      padding-top: 5px;
      padding-right: 25px;
    }

  .ul_user {
    list-style: none;
  }

    .ul_user li {
      padding-top: 5px;
    }

  .send {
    position: relative;
    background: #eae7e7;
    border-radius: 5px; /* 圆角 */
    padding-top: 4px;
    padding-left: 5px;
    margin-top: 13px;
  }

    .send .arrow {
      position: absolute;
      top: -16px;
      font-size: 0;
      border: solid 8px;
      border-color: #fff #fff #eae7e7 #fff;
    }
</style>
<h3>@ViewBag.Title 在线人数:<span id="sapnUserTotal">0</span>人</h3>
<p class="container text-left">
  <p class="p_left">
    <ul class="ul" id="discussion"></ul>
    <textarea rows="5" class="form-control" id="message" maxlength="500" placeholder="开始聊天. . ." style="max-width: 100%"></textarea><br />
    <input type="button" id="sendmessage" value="发 送" class="btn btn-default" />
    <input type="hidden" id="displayname" />
  </p>
  <p class="p_right">
    <ul id="users" class="ul_user"></ul>
  </p>
</p>

<script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script>
@*<script src="~/chat/hubs"></script>*@
登录后复制

客户端这里写法大致有两种选择,一种直接使用生成的代理来操作,一种不用自动生成的代理采用手动创建代理的方式;为了内容的简洁性,这里只简单讲解下自动生成的代理方式,而更多的是分享手动创建代理链接的方式;

使用生成的代理获取链接

首先,我们需要通过Script标签来引用一下自动生成代理的路径: <script src="~/chat/hubs"></script> ,注意啦这里的路径/chat对应的就是咋们在前面Startup.cs文件中配置 app.MapSignalR("/chat" 路径,而后面/hubs固定的写法(至少目前我还没更多的试验过),只有先应用了这个~/chat/hubs,才能在后面使用生成的代理,先上段代码:

var chat = $.connection.chatHub;
    chat.client.newUser = function (user) {
      $("#users").append(&#39; <li><strong>&#39; + user.NickName + &#39;[&#39; + user.TransportMethod + &#39;]</strong></li>&#39;);
    };

    chat.client.userList = function (users) {
      console.log(users);
      $("#sapnUserTotal").html(users.length);
      $.each(users, function (i, item) {
        $("#users").append(&#39; <li>[&#39; + item.TransportMethod + &#39;] <strong>&#39; + item.NickName + &#39;</strong>(&#39; + item.Id + &#39;)</li>&#39;);
      });
    };
    chat.client.addNewMessageToPage = function (user, message) {
      console.log(user);
      $("#discussion").append(&#39; <li ><span><strong>&#39; + user.NickName + &#39;[&#39; + user.TransportMethod + &#39;]</strong>:</span><p class="send">&#39; + message + &#39;<p class="arrow"></p></p></li>&#39;);
    };
  //connection.hub.start({ transport: [&#39;webSockets&#39;, &#39;longPolling&#39;] }).done(function () {
    //  my.TransportMethod = connection.hub.transport.name;
    //  chat.server.addUser(my);

    //  $(&#39;#sendmessage&#39;).click(function () {
    //    //console.log(chat);
    //    var content = $.trim($(&#39;#message&#39;).val());
    //    if (content.length <= 0) { $(&#39;#message&#39;).val(&#39;&#39;).focus(); return; }
    //    chat.server.sendAll(my, content);
    //    $(&#39;#message&#39;).val(&#39;&#39;).focus();
    //  });
    //}).fail(function () {
    //  alert("链接聊天室失败,请重新刷新页面。");
    //});
登录后复制

咋们逐步来解析下代码注意点:

1. var chat = $.connection.chatHub; 这里的chatHub对应的就是咋们创建的并继承Hub的ChatHub类,由于js变量开头都是小写,所以这里是chatHub,这句活就表示链接到咋们后端了ChatHub类了,然后就可以使用里面的方法啦(这种有点类似于早期的webform中某种ajax请求的写法)

2. 通过chat.client.xxx来接收服务端通知的消息,而这个xxx对应的方法名称和咋们后端的Clients.All.xxx,本章实例对应的是:chat.client.userList = function (users){}对应Clients.All.userList(_Users);这样后端就能直接通知客户端的对应方法了;注意这里我后端Clients.All用的是通知全部客户端的意思,如果您需要通知指定的链接需要用到的是: T Client(string connectionId); 方法

3. chat.client是后端调用客户端,那相对的chat.server就是客户端请求服务端,和上面一样通过chat.server.xxx来指定请求的服务端方法,注意这个时候服务端方法指的是继承类Hub的子类的公共方法(本篇对应的是:chat.server.sendAll(my, content)对应ChatHub.cs文件中的 public void SendAll(MoHubUser user, string message) 函数)

4. connection.hub.start({ transport: [&#39;webSockets&#39;, &#39;longPolling&#39;] }) 来指定运行的交互协议

以上就是使用生成代理的方式,按照上面的注意点来写应该不是问题;

使用手动创建反向代理来链接

不采用生成的代码的方式,我们只需要修改前端就行了,后台代码不用变或设置不用变动;首先我们把上面说的Script引用自动代理的代码去掉,因为这个时候不需要了,我们还是先上代码:

var my = { NickName: "神牛001", TransportMethod: "" };
    var connection = $.hubConnection("/chat/hubs");
    var chat = connection.createHubProxy(&#39;chatHub&#39;);

    chat.on("userList", function (users) {
      console.log(users);
      $("#sapnUserTotal").html(users.length);
      $("#users").html("");
      $.each(users, function (i, item) {
        $("#users").append(&#39; <li>[&#39; + item.TransportMethod + &#39;] <strong>&#39; + item.NickName + &#39;</strong>(&#39; + item.Id + &#39;)</li>&#39;);
      });
    });

    chat.on("addNewMessageToPage", function (user, message) {
      console.log(user);
      $("#discussion").append(&#39; <li ><span><strong>&#39; + user.NickName + &#39;[&#39; + user.TransportMethod + &#39;]</strong>:</span><p class="send">&#39; + message + &#39;<p class="arrow"></p></p></li>&#39;);

      var p = document.getElementById(&#39;discussion&#39;);
      //p.scrollTop = p.scrollHeight;
      p.scrollTop = 999999;
    });

    var nickName = prompt("请输入一个昵称:", my.NickName);
    my.NickName = nickName.length > 0 ? nickName : my.NickName;
    $(&#39;#displayname&#39;).val(nickName);
    $(&#39;#message&#39;).focus();
   

    connection.start({ transport: [&#39;webSockets&#39;, &#39;longPolling&#39;] }).done(function () {

      my.TransportMethod = connection.transport.name;
      //console.log(my.TransportMethod);
      chat.invoke("addUser", my);

      $(&#39;#sendmessage&#39;).click(function () {
        var content = $.trim($(&#39;#message&#39;).val());
        if (content.length <= 0) { $(&#39;#message&#39;).val(&#39;&#39;).focus(); return; }

        chat.invoke("sendAll", my, content);
        $(&#39;#message&#39;).val(&#39;&#39;).focus();
      });
    });
登录后复制

同样列出如下注意点:

1.  var connection = $.hubConnection("/chat/hubs"); 创建链接,这里的path同样对应后端的 app.MapSignalR("/chat" ,路径保持一致

2.  var chat = connection.createHubProxy('chatHub'); 来创建反向代理链接,这里的name:chatHub对应的是后端的ChatHub类名称

3. 通过on("xxx",function(){})函数来绑定服务端通知客户端的事件,xxx对应Clients.All.xxx中的xxx

4.  connection.start({ transport: ['webSockets', 'longPolling'] }) 来设置允许的链接方式,并开始链接

5. connection.transport.name来获取链接的方式名称,默认start不设置的话有这么几种:webSockets,foreverFrame,serverSentEvents,longPolling

6. chat.invoke("xxx", param1, param2)通过invoke来映射继承类Hub的类的公共方法,这里实例对应的是: chat.invoke("sendAll", my, content) 对应 public void SendAll(MoHubUser user, string message)

以上是SignalR实现实时Web聊天的实例代码的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何利用React和WebSocket构建实时聊天应用 如何利用React和WebSocket构建实时聊天应用 Sep 26, 2023 pm 07:46 PM

如何利用React和WebSocket构建实时聊天应用引言:随着互联网的快速发展,实时通讯越来越受到人们的关注。实时聊天应用已经成为现代社交和工作生活中不可或缺的一部分。本文将介绍如何利用React和WebSocket构建一个简单的实时聊天应用,并提供具体的代码示例。一、技术准备在开始构建实时聊天应用之前,我们需要准备以下技术和工具:React:一个用于构建

如何在PHP中实现实时聊天功能 如何在PHP中实现实时聊天功能 Sep 24, 2023 pm 04:49 PM

如何在PHP中实现实时聊天功能随着社交媒体和即时通讯应用的普及,实时聊天功能已经成为许多网站和应用的标配。在本文中,我们将探讨如何使用PHP语言实现实时聊天功能,以及一些代码示例。使用WebSocket协议实时聊天功能通常需要使用WebSocket协议,它允许服务器与客户端之间进行双向通信。在PHP中,我们可以使用Ratchet库来实现WebSocket服务

利用workerman和HTML5 WebSocket技术实现实时在线聊天 利用workerman和HTML5 WebSocket技术实现实时在线聊天 Sep 09, 2023 am 11:00 AM

利用Workerman和HTML5WebSocket技术实现实时在线聊天引言:随着互联网的迅速发展和智能手机的普及,实时在线聊天已经成为人们日常生活中不可或缺的一部分。为了满足用户的需求,Web开发者们不断寻找更高效、更实时的聊天解决方案。本文将介绍如何结合PHP的框架Workerman和HTML5的WebSocket技术,实现一个简单的实时在线聊天系统。

如何使用Layui框架开发一个实时聊天应用 如何使用Layui框架开发一个实时聊天应用 Oct 24, 2023 am 10:48 AM

如何使用Layui框架开发一个实时聊天应用引言:现在社交网络的发展已经越来越迅猛,人们的沟通方式也从传统的电话、短信逐渐转向实时聊天。实时聊天应用已经成为人们生活中不可或缺的一部分,它提供了方便快捷的沟通方式。本文将介绍如何使用Layui框架开发一个实时聊天应用,其中包括了具体的代码实例。一、选择合适的架构在开始开发之前,我们需要选择一个合适的架构来支持实时

C#的就业前景如何 C#的就业前景如何 Oct 19, 2023 am 11:02 AM

无论您是初学者还是有经验的专业人士,掌握C#将为您的职业发展铺平道路。

分享几个.NET开源的AI和LLM相关项目框架 分享几个.NET开源的AI和LLM相关项目框架 May 06, 2024 pm 04:43 PM

当今人工智能(AI)技术的发展如火如荼,它们在各个领域都展现出了巨大的潜力和影响力。今天大姚给大家分享4个.NET开源的AI模型LLM相关的项目框架,希望能为大家提供一些参考。https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel是一种开源的软件开发工具包(SDK),旨在将大型语言模型(LLM)如OpenAI、Azure

PHP MVC 架构:构建面向未来的 Web 应用程序 PHP MVC 架构:构建面向未来的 Web 应用程序 Mar 03, 2024 am 09:01 AM

引言在当今快速发展的数字世界中,构建健壮、灵活且可维护的WEB应用程序至关重要。PHPmvc架构提供了实现这一目标的理想解决方案。MVC(模型-视图-控制器)是一种广泛使用的设计模式,可以将应用程序的各个方面分离为独立的组件。MVC架构的基础MVC架构的核心原理是分离关注点:模型:封装应用程序的数据和业务逻辑。视图:负责呈现数据并处理用户交互。控制器:协调模型和视图之间的交互,管理用户请求和业务逻辑。PHPMVC架构phpMVC架构遵循传统MVC模式,但也引入了语言特定的功能。以下是PHPMVC

PHP实时聊天系统的消息阅读状态和未读消息提醒 PHP实时聊天系统的消息阅读状态和未读消息提醒 Aug 13, 2023 pm 06:58 PM

PHP实时聊天系统的消息阅读状态和未读消息提醒在现代社交网络和即时通讯应用中,消息阅读状态和未读消息提醒是必不可少的功能。在PHP实时聊天系统中,我们可以通过一些简单的代码来实现这些功能。本文将为大家介绍如何利用PHP来实现消息阅读状态和未读消息提醒的功能,并提供相应的代码示例。消息阅读状态首先,我们需要在数据库中的消息表中添加一个字段来表示消息的阅读状态。

See all articles