Asp.net mvc使用SignaIR
一、Asp.net SignalR 是个什么东东
Asp.net SignalR是微软为实现实时通信的一个类库。一般情况下,SignalR会使用JavaScript的长轮询(long polling)的方式来实现客户端和服务器通信,随着Html5中WebSockets出现,SignalR也支持WebSockets通信。另外SignalR开发的程序不仅仅限制于宿主在IIS中,也可以宿主在任何应用程序,包括控制台,客户端程序和Windows服务等,另外还支持Mono,这意味着它可以实现跨平台部署在Linux环境下。
SignalR内部有两类对象:
- Http持久连接(Persisten Connection)对象:用来解决长时间连接的功能。还可以由客户端主动向服务器要求数据,而服务器端不需要实现太多细节,只需要处理PersistentConnection 内所提供的五个事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。
- Hub(集线器)对象:用来解决实时(realtime)信息交换的功能,服务端可以利用URL来注册一个或多个Hub,只要连接到这个Hub,就能与所有的客户端共享发送到服务器上的信息,同时服务端可以调用客户端的脚本。
SignalR将整个信息的交换封装起来,客户端和服务器都是使用JSON来沟通的,在服务端声明的所有Hub信息,都会生成JavaScript输出到客户端,.NET则依赖Proxy来生成代理对象,而Proxy的内部则是将JSON转换成对象。
客户端和服务端的具体交互情况如下图所示:
从上面的介绍可以看出,SignalR既然是为实时而生的,这样就决定了其使用场所。具体适用情景有如下几点:
- 聊天室,如在线客服系统,IM系统等
- 股票价格实时更新
- 消息的推送服务
- 游戏中人物位置的实时推送
目前,我所在公司在开发的就是在线客服系统。
三、使用Asp.net SignalR在Web端实现广播消息
通过第二部分的介绍,相信大家对Asp.net SignalR有了一个初步的了解,接下来通过两个例子来让大家加深对SignalR运行机制的理解。第一个例子就是在Web端如何使用SignalR来实现广播消息。
- 使用Visual Studio 2013,创建一个MVC工程
- 通过Nuget安装SignalR包。右键引用-》选择管理Nuget程序包-》在出现的窗口中输入SignalR来找到SignalR包进行安装。
- 安装SignalR成功后,SignalR库的脚本将被添加进Scripts文件夹下。具体如下图所示:
4. 向项目中添加一个SignalR集线器(v2)并命名为ServerHub。
5. 将下面代码填充到刚刚创建的ServerHub类中。
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using System; namespace SignalRQuickStart
{public class ServerHub : Hub
{
private static readonly char[] Constant =
{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z'
}; /// <summary>
/// 供客户端调用的服务器端代码
/// </summary>
/// <param name="message"></param>
public void Send(string message)
{
var name = GenerateRandomName(4); // 调用所有客户端的sendMessage方法
Clients.All.sendMessage(name, message);
} /// <summary>
/// 产生随机用户名函数
/// </summary>
/// <param name="length">用户名长度</param>
/// <returns></returns>
public static string GenerateRandomName(int length)
{
var newRandom = new System.Text.StringBuilder(62);
var rd = new Random();
for (var i = 0; i < length; i++)
{
newRandom.Append(Constant[rd.Next(62)]);
}
return newRandom.ToString();
}
}
}
6. 创建一个Startup类,如果开始创建MVC项目的时候没有更改身份验证的话,这个类会默认添加的,如果已有就不需要重复添加了。按照如下代码更新Startup类。
public class Startup
{
public void Configuration(IAppBuilder app)
{
// 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888
// 配置集线器
app.MapSignalR();
}
}
7. 在Home控制器中创建一个Home Action方法
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
} public ActionResult About()
{
ViewBag.Message = "Your application description page."; return View();
} public ActionResult Contact()
{
ViewBag.Message = "Your contact page."; return View();
} public ActionResult Chat()
{
return View();
}
}
8. 在Views文件中Home文件夹中创建一个Chat视图,视图代码如下所示:
@{
ViewBag.Title = "聊天窗口";
} <h2>Chat</h2> <div class="container">
<input type="text" id="message" />
<input type="button" id="sendmessage" value="Send" />
<input type="hidden" id="displayname" />
<ul id="discussion"></ul>
</div> @section scripts
{
<!--引用SignalR库. -->
<script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
<!--引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 -->
<script src="~/signalr/hubs"></script> <script>
$(function () {
// 引用自动生成的集线器代理
var chat = $.connection.serverHub;
// 定义服务器端调用的客户端sendMessage来显示新消息 chat.client.sendMessage = function (name, message) {
// 向页面添加消息
$('#discussion').append('<li><strong>' + htmlEncode(name)
+ '</strong>: ' + htmlEncode(message) + '</li>');
}; // 设置焦点到输入框
$('#message').focus();
// 开始连接服务器
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// 调用服务器端集线器的Send方法
chat.server.send($('#message').val());
// 清空输入框信息并获取焦点
$('#message').val('').focus();
});
});
}); // 为显示的消息进行Html编码
function htmlEncode(value) {
var encodedValue = $('<div />').text(value).html();
return encodedValue;
}
</script>
}
9. 修改App_Start文件夹内的RoutConfig类,将Action方法默认设置为Chat.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Chat", id = UrlParameter.Optional }
);
}
}
到此,我们的例子就实现完成了,接下来我们先来看看运行效果,之后再来解释到底SignalR是如何来完成广播消息的。运行的运行结果如下。
从运行结果,你可以发现,在任何一个窗口输入信息并发送,所有客户端将收到该消息。这样的效果在实际应用中很多,如QQ,一登录QQ的时候都会推送腾讯广告消息。
看完了运行结果,接下来我们来分析下代码,进而来剖析下SignalR到底是如何工作的。
按照B/S模式来看,运行程序的时候,Web页面就与SignalR的服务建立了连接,具体的建立连接的代码就是:$.connection.hub.start()。这句代码的作用就是与SignalR服务建立连接,后面的done函数表明建立连接成功后为发送按钮注册了一个click事件,当客户端输入内容点击发送按钮后,该Click事件将会触发,触发执行的操作为: chat.server.send($('#message').val())。这句代码表示调用服务端的send函数,而服务端的Send韩式又是调用所有客户端的sendMessage函数,而客户端中sendMessage函数就是将信息添加到对应的消息列表中。这样就实现了广播消息的功能了。
看到这里,有人是否会有疑问,前面的实现都只用到了集线器对象,而没有用到持久连接对象。其实并不是如此,$.connection这句代码就是使用持久连接对象,当然你也可以在重新OnConnected方法来查看监控客户端的连接情况,更新的代码如下所示:
public class ServerHub : Hub
{
private static readonly char[] Constant =
{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z'
}; /// <summary>
/// 供客户端调用的服务器端代码
/// </summary>
/// <param name="message"></param>
public void Send(string message)
{
var name = GenerateRandomName(4); // 调用所有客户端的sendMessage方法
Clients.All.sendMessage(name, message);
} /// <summary>
/// 客户端连接的时候调用
/// </summary>
/// <returns></returns>
public override Task OnConnected()
{
Trace.WriteLine("客户端连接成功");
return base.OnConnected();
} /// <summary>
/// 产生随机用户名函数
/// </summary>
/// <param name="length">用户名长度</param>
/// <returns></returns>
public static string GenerateRandomName(int length)
{
var newRandom = new System.Text.StringBuilder(62);
var rd = new Random();
for (var i = 0; i < length; i++)
{
newRandom.Append(Constant[rd.Next(62)]);
}
return newRandom.ToString();
}
}
这样在运行页面的时候,将在输出窗口看到“客户端连接成功”字样。运行效果如下图所示:
在第二部分介绍的时候说道,在服务端声明的所有Hub信息,都会生成JavaScript输出到客户端,为了验证这一点,可以在Chrome中F12来查看源码就明白了,具体如下图所示:
看到上图,你也就明白了为什么Chat.cshtml页面需要引入"signalr/hubs"脚本库了吧。
<!--引用SignalR库. -->
<script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
<!--引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 -->
<script src="~/signalr/hubs"></script>
本文所有源码:SignalR快速入门
文章摘自:https://www.cnblogs.com/zhili/p/SignalRQuickStart.html
Asp.net mvc使用SignaIR的更多相关文章
- ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库
在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...
- 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus
最新的Mono 4.4已经支持运行asp.net mvc5项目,有的同学听了这句话就兴高采烈的拿起Visual Studio 2015创建了一个mvc 5的项目,然后部署到Mono上,浏览下发现一堆错 ...
- 一百元的智能家居——Asp.Net Mvc Api+讯飞语音+Android+Arduino
大半夜的,先说些废话提提神 如今智能家居已经不再停留在概念阶段,高大上的科技公司都已经推出了自己的部分或全套的智能家居解决方案,不过就目前的现状而言,大多还停留在展厅阶段,还没有广泛的推广起来,有人说 ...
- Asp.net MVC 传递数据 从前台到后台,包括单个对象,多个对象,集合
今天为大家分享下 Asp.net MVC 将数据从前台传递到后台的几种方式. 环境:VS2013,MVC5.0框架 1.基本数据类型 我们常见有传递 int, string, bool, double ...
- ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第一章:创建基本的MVC Web站点
在这一章中,我们将学习如何使用基架快速搭建和运行一个简单的Microsoft ASP.NET MVC Web站点.在我们马上投入学习和编码之前,我们首先了解一些有关ASP.NET MVC和Entity ...
- ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之目录导航
ASP.NET MVC with Entity Framework and CSS是2016年出版的一本比较新的.关于ASP.NET MVC.EF以及CSS技术的图书,我将尝试着翻译本书以供日后查阅. ...
- ASP.NET MVC开发:Web项目开发必备知识点
最近加班加点完成一个Web项目,使用Asp.net MVC开发.很久以前接触的Asp.net开发还是Aspx形式,什么Razor引擎,什么MVC还是这次开发才明白,可以算是新手. 对新手而言,那进行A ...
- ASP.NET MVC原理
仅此一文让你明白ASP.NET MVC原理 ASP.NET MVC由以下两个核心组成部分构成: 一个名为UrlRoutingModule的自定义HttpModule,用来解析Controller与 ...
- ASP.NET MVC——模型绑定
这篇文章我们来讲讲模型绑定(Model Binding),其实在初步了解ASP.NET MVC之后,大家可能都会产生一个疑问,为什么URL片段最后会转换为例如int型或者其他类型的参数呢?这里就不得不 ...
随机推荐
- Ajax向服务器端发送请求
Ajax向服务器端发送请求 Ajax的应用场景 页面上拉加载更多数据 列表数据无刷新分页 表单项离开焦点数据验证 搜索框提示文字下拉列表 Ajax运行原理 Ajax 相当于浏览器发送请求与接收响应的代 ...
- 利用redis未授权访问漏洞(windows版)
0x00 原理 首先需要知道的是,redis是一种非关系型数据库.它在默认情况下,绑定在0.0.0.0:6379 ,若不采取相关策略,比如添加防火墙限制非信任IP访问,会使得redis服务暴露到公 ...
- Java核心技术卷阅读随笔--第4章【对象与类】
对 象 与 类 4.1 面向对象程序设计概述 面向对象程序设计(简称 OOP) 是当今主流的程序设计范型, 它已经取代了 20 世纪 70 年代的" 结构化" 过程化程序设计开发技 ...
- 十一、.net core(.NET 6)搭建ElasticSearch(ES)系列之ElasticSearch、head-master、Kibana环境搭建
搭建ElasticSearch+Kibana环境 前提条件:已经配置好JDK环境以及Nodejs环境.如果还未配置,请查看我的上一篇博客内容,有详细配置教程. 先下载ElasticSearch(以下文 ...
- Linux下使用LVM管理(扩展/缩小/删除)
LVM的工作原理 LVM( Logical Volume Manager)逻辑卷管理,是在磁盘分区和文件系统之间添加的一个逻辑层,来为文件系统屏蔽下层磁盘分区布局,提供一个抽象的盘卷,在盘卷上建立文件 ...
- sql 处理数据字段为NULL 若不为空则显示该值,若为空转换成别的值。
第一种方法: 判断字段是否为空,如果为空转成你要的字符 1.oracle : nvl("字段名",'转换后的值')://字段名是双引号,转换后的值是单引号 2.sql Server ...
- 强烈推荐!15 个Github 顶级Java教程类开源项目
大家好,我是 Guide 哥!今天给大家推荐 15 个新手也能看懂的 Java 教程方向的开源项目.这些项目无论是对于你学习 Java 还是准备 Java 方向的面试都非常有帮助. 正如我第一个要推荐 ...
- Java8新特性代码示例(附注释)- 方法引用,Optional, Stream
/** * java8中的函数式接口,java中规定:函数式接口必须只有一个抽象方法,可以有多个非抽象方法,同时,如果继承实现了 * Object中的方法,那么也是合法的 * <p> * ...
- gRPC趁现在还没大火,抢先了解一下
前言 系统分布式已经成为程序员的家常,将大型单体划分为相对简单的小模块,分散系统能力,提升系统扩展性.功能模块复用性等:各功能模块之间肯定会有很多数据共享和交互的应用场景,那就避免不了各模块之间的通信 ...
- Golang获取CPU、内存、硬盘使用率
Golang获取CPU.内存.硬盘使用率 工具包 go get github.com/shirou/gopsutil 实现 func GetCpuPercent() float64 { percent ...