视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Asp.net MVC SignalR来做实时Web聊天实例代码
2020-11-27 22:35:41 责编:小采
文档


本章和大家分享的内容是使用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 static IAppBuilder MapSignalR(this IAppBuilder builder, string 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">
 .div_left {
 width: 70%;
 float: left;
 }

 .div_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>
<div class="container text-left">
 <div class="div_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" />
 </div>
 <div class="div_right">
 <ul id="users" class="ul_user"></ul>
 </div>
</div>

<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(' <li><strong>' + user.NickName + '[' + user.TransportMethod + ']</strong></li>');
 };

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

 // $('#sendmessage').click(function () {
 // //console.log(chat);
 // var content = $.trim($('#message').val());
 // if (content.length <= 0) { $('#message').val('').focus(); return; }
 // chat.server.sendAll(my, content);
 // $('#message').val('').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: ['webSockets', 'longPolling'] }) 来指定运行的交互协议

下载本文
显示全文
专题