Asp.net SignalR快速入门

一、前言

  之前半年时间感觉自己有点浮躁,导致停顿了半年多的时间没有更新博客,今天重新开始记录博文,希望自己可以找回初心,继续沉淀。由于最近做的项目中用到SignalR技术,所以打算总结下Asp.net SignalR的相关内容,希望对刚接触或者接触不多的朋友有所帮助。今天的专题就是让大家可以快速的上手Asp.net SignalR。废话不多说了,下面正式进入今天专题的内容。

二、Asp.net SignalR 是个什么东东

  Asp.net SignalR是微软为实现实时通信的一个类库。一般情况下,SignalR会使用JavaScript的长轮询(long polling)的方式来实现客户端和服务器通信,随着Html5中WebSockets出现,SignalR也支持WebSockets通信。另外SignalR开发的程序不仅仅限制于宿主在IIS中,也可以宿主在任何应用程序,包括控制台,客户端程序和Windows服务等,另外还支持Mono,这意味着它可以实现跨平台部署在Linux环境下。

  SignalR内部有两类对象:

  1. Http持久连接(Persisten Connection)对象:用来解决长时间连接的功能。还可以由客户端主动向服务器要求数据,而服务器端不需要实现太多细节,只需要处理PersistentConnection 内所提供的五个事件:OnConnected, OnReconnected, OnReceived, OnError 和 OnDisconnect 即可。
  2. Hub(集线器)对象:用来解决实时(realtime)信息交换的功能,服务端可以利用URL来注册一个或多个Hub,只要连接到这个Hub,就能与所有的客户端共享发送到服务器上的信息,同时服务端可以调用客户端的脚本。

  SignalR将整个信息的交换封装起来,客户端和服务器都是使用JSON来沟通的,在服务端声明的所有Hub信息,都会生成JavaScript输出到客户端,.NET则依赖Proxy来生成代理对象,而Proxy的内部则是将JSON转换成对象。

  客户端和服务端的具体交互情况如下图所示:

  从上面的介绍可以看出,SignalR既然是为实时而生的,这样就决定了其使用场所。具体适用情景有如下几点:

  1. 聊天室,如在线客服系统,IM系统等
  2. 股票价格实时更新
  3. 消息的推送服务
  4. 游戏中人物位置的实时推送

  目前,我所在公司在开发的就是在线客服系统。

三、使用Asp.net SignalR在Web端实现广播消息

  通过第二部分的介绍,相信大家对Asp.net SignalR有了一个初步的了解,接下来通过两个例子来让大家加深对SignalR运行机制的理解。第一个例子就是在Web端如何使用SignalR来实现广播消息。

  1. 使用Visual Studio 2013,创建一个MVC工程
  2. 通过Nuget安装SignalR包。右键引用-》选择管理Nuget程序包-》在出现的窗口中输入SignalR来找到SignalR包进行安装。
  3. 安装SignalR成功后,SignalR库的脚本将被添加进Scripts文件夹下。具体如下图所示:

  4. 向项目中添加一个SignalR集线器(v2)并命名为ServerHub。

  5. 将下面代码填充到刚刚创建的ServerHub类中。

  1. using Microsoft.AspNet.SignalR;
  2. using Microsoft.AspNet.SignalR.Hubs;
  3. using System;
  4.  
  5. namespace SignalRQuickStart
  6. {public class ServerHub : Hub
  7. {
  8. private static readonly char[] Constant =
  9. {
  10. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  11. 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
  12. 'w', 'x', 'y', 'z',
  13. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  14. 'W', 'X', 'Y', 'Z'
  15. };
  16.  
  17. /// <summary>
  18. /// 供客户端调用的服务器端代码
  19. /// </summary>
  20. /// <param name="message"></param>
  21. public void Send(string message)
  22. {
  23. var name = GenerateRandomName(4);
  24.  
  25. // 调用所有客户端的sendMessage方法
  26. Clients.All.sendMessage(name, message);
  27. }
  28.  
  29. /// <summary>
  30. /// 产生随机用户名函数
  31. /// </summary>
  32. /// <param name="length">用户名长度</param>
  33. /// <returns></returns>
  34. public static string GenerateRandomName(int length)
  35. {
  36. var newRandom = new System.Text.StringBuilder(62);
  37. var rd = new Random();
  38. for (var i = 0; i < length; i++)
  39. {
  40. newRandom.Append(Constant[rd.Next(62)]);
  41. }
  42. return newRandom.ToString();
  43. }
  44. }
  45. }

  6. 创建一个Startup类,如果开始创建MVC项目的时候没有更改身份验证的话,这个类会默认添加的,如果已有就不需要重复添加了。按照如下代码更新Startup类。

  7. 在Home控制器中创建一个Home Action方法

  1. public class HomeController : Controller
  2. {
  3. public ActionResult Index()
  4. {
  5. return View();
  6. }
  7.  
  8. public ActionResult About()
  9. {
  10. ViewBag.Message = "Your application description page.";
  11.  
  12. return View();
  13. }
  14.  
  15. public ActionResult Contact()
  16. {
  17. ViewBag.Message = "Your contact page.";
  18.  
  19. return View();
  20. }
  21.  
  22. public ActionResult Chat()
  23. {
  24. return View();
  25. }
  26. }

  8. 在Views文件中Home文件夹中创建一个Chat视图,视图代码如下所示:

  1. @{
  2. ViewBag.Title = "聊天窗口";
  3. }
  4.  
  5. <h2>Chat</h2>
  6.  
  7. <div class="container">
  8. <input type="text" id="message" />
  9. <input type="button" id="sendmessage" value="Send" />
  10. <input type="hidden" id="displayname" />
  11. <ul id="discussion"></ul>
  12. </div>
  13.  
  14. @section scripts
  15. {
  16. <!--引用SignalR库. -->
  17. <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
  18. <!--引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 -->
  19. <script src="~/signalr/hubs"></script>
  20.  
  21. <script>
  22. $(function () {
  23. // 引用自动生成的集线器代理
  24. var chat = $.connection.serverHub;
  25. // 定义服务器端调用的客户端sendMessage来显示新消息
  26.  
  27. chat.client.sendMessage = function (name, message) {
  28. // 向页面添加消息
  29. $('#discussion').append('<li><strong>' + htmlEncode(name)
  30. + '</strong>: ' + htmlEncode(message) + '</li>');
  31. };
  32.  
  33. // 设置焦点到输入框
  34. $('#message').focus();
  35. // 开始连接服务器
  36. $.connection.hub.start().done(function () {
  37. $('#sendmessage').click(function () {
  38. // 调用服务器端集线器的Send方法
  39. chat.server.send($('#message').val());
  40. // 清空输入框信息并获取焦点
  41. $('#message').val('').focus();
  42. });
  43. });
  44. });
  45.  
  46. // 为显示的消息进行Html编码
  47. function htmlEncode(value) {
  48. var encodedValue = $('<div />').text(value).html();
  49. return encodedValue;
  50. }
  51. </script>
  52. }

  9. 修改App_Start文件夹内的RoutConfig类,将Action方法默认设置为Chat.

  1. public class RouteConfig
  2. {
  3. public static void RegisterRoutes(RouteCollection routes)
  4. {
  5. routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  6. routes.MapRoute(
  7. name: "Default",
  8. url: "{controller}/{action}/{id}",
  9. defaults: new { controller = "Home", action = "Chat", id = UrlParameter.Optional }
  10. );
  11. }
  12. }

  到此,我们的例子就实现完成了,接下来我们先来看看运行效果,之后再来解释到底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方法来查看监控客户端的连接情况,更新的代码如下所示:

  1. public class ServerHub : Hub
  2. {
  3. private static readonly char[] Constant =
  4. {
  5. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  6. 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
  7. 'w', 'x', 'y', 'z',
  8. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  9. 'W', 'X', 'Y', 'Z'
  10. };
  11.  
  12. /// <summary>
  13. /// 供客户端调用的服务器端代码
  14. /// </summary>
  15. /// <param name="message"></param>
  16. public void Send(string message)
  17. {
  18. var name = GenerateRandomName(4);
  19.  
  20. // 调用所有客户端的sendMessage方法
  21. Clients.All.sendMessage(name, message);
  22. }
  23.  
  24. /// <summary>
  25. /// 客户端连接的时候调用
  26. /// </summary>
  27. /// <returns></returns>
  28. public override Task OnConnected()
  29. {
  30. Trace.WriteLine("客户端连接成功");
  31. return base.OnConnected();
  32. }
  33. /// <summary>
  34. /// 产生随机用户名函数
  35. /// </summary>
  36. /// <param name="length">用户名长度</param>
  37. /// <returns></returns>
  38. public static string GenerateRandomName(int length)
  39. {
  40. var newRandom = new System.Text.StringBuilder(62);
  41. var rd = new Random();
  42. for (var i = 0; i < length; i++)
  43. {
  44. newRandom.Append(Constant[rd.Next(62)]);
  45. }
  46. return newRandom.ToString();
  47. }
  48. }

  这样在运行页面的时候,将在输出窗口看到“客户端连接成功”字样。运行效果如下图所示:

  在第二部分介绍的时候说道,在服务端声明的所有Hub信息,都会生成JavaScript输出到客户端,为了验证这一点,可以在Chrome中F12来查看源码就明白了,具体如下图所示:

  看到上图,你也就明白了为什么Chat.cshtml页面需要引入"signalr/hubs"脚本库了吧。

  1. <!--引用SignalR库. -->
  2. <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
  3. <!--引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 -->
  4. <script src="~/signalr/hubs"></script>

四、在桌面程序中如何使用Asp.net SignalR

  上面部分介绍了SignalR在Asp.net MVC 中的实现,这部分将通过一个例子来看看SignalR在WPF或WinForm是如何使用的。其实这部分实现和Asp.net MVC中非常相似,主要不同在于,Asp.net MVC中的SignalR服务器寄宿在IIS中,而在WPF中应用,我们把SignalR寄宿在WPF客户端中。

下面让我们看看SignalR服务端的实现。

  1. /// <summary>
  2. /// 启动SignalR服务,将SignalR服务寄宿在WPF程序中
  3. /// </summary>
  4. private void StartServer()
  5. {
  6. try
  7. {
  8. SignalR = WebApp.Start(ServerUri); // 启动SignalR服务
  9. }
  10. catch (TargetInvocationException)
  11. {
  12. WriteToConsole("一个服务已经运行在:" + ServerUri);
  13. // Dispatcher回调来设置UI控件状态
  14. this.Dispatcher.Invoke(() => ButtonStart.IsEnabled = true);
  15. return;
  16. }
  17.  
  18. this.Dispatcher.Invoke(() => ButtonStop.IsEnabled = true);
  19. WriteToConsole("服务已经成功启动,地址为:" + ServerUri);
  20. }
  21.  
  22. public class ChatHub : Hub
  23. {
  24. public void Send(string name, string message)
  25. {
  26. Clients.All.addMessage(name, message);
  27. }
  28.  
  29. public override Task OnConnected()
  30. {
  31. //
  32. Application.Current.Dispatcher.Invoke(() =>
  33. ((MainWindow)Application.Current.MainWindow).WriteToConsole("客户端连接,连接ID是: " + Context.ConnectionId));
  34.  
  35. return base.OnConnected();
  36. }
  37.  
  38. public override Task OnDisconnected(bool stopCalled)
  39. {
  40. Application.Current.Dispatcher.Invoke(() =>
  41. ((MainWindow)Application.Current.MainWindow).WriteToConsole("客户端断开连接,连接ID是: " + Context.ConnectionId));
  42.  
  43. return base.OnDisconnected(true);
  44. }
  45. }
  46.  
  47. public class Startup
  48. {
  49. public void Configuration(IAppBuilder app)
  50. {
  51. // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888
  52. // 允许CORS跨域
  53. //app.UseCors(CorsOptions.AllowAll);
  54. app.MapSignalR();
  55. }
  56. }

  通过上面的代码,我们SignalR服务端的实现就完成了,其实现逻辑与Asp.net MVC的代码类似。

  接下来,让我们看看,WPF客户端是如何连接和与服务器进行通信的。具体客户端的实现如下:

  1. public IHubProxy HubProxy { get; set; }
  2. const string ServerUri = "http://localhost:8888/signalr";
  3. public HubConnection Connection { get; set; }
  4.  
  5. public MainWindow()
  6. {
  7. InitializeComponent();
  8.  
  9. // 窗口启动时开始连接服务
  10. ConnectAsync();
  11. }
  12.  
  13. /// <summary>
  14. /// 发送消息
  15. /// </summary>
  16. /// <param name="sender"></param>
  17. /// <param name="e"></param>
  18. private void ButtonSend_Click(object sender, RoutedEventArgs e)
  19. {
  20. // 通过代理来调用服务端的Send方法
  21. // 服务端Send方法再调用客户端的AddMessage方法将消息输出到消息框中
  22. HubProxy.Invoke("Send", GenerateRandomName(4), TextBoxMessage.Text.Trim());
  23.  
  24. TextBoxMessage.Text = String.Empty;
  25. TextBoxMessage.Focus();
  26. }
  27.  
  28. private async void ConnectAsync()
  29. {
  30. Connection = new HubConnection(ServerUri);
  31. Connection.Closed += Connection_Closed;
  32.  
  33. // 创建一个集线器代理对象
  34. HubProxy = Connection.CreateHubProxy("ChatHub");
  35.  
  36. // 供服务端调用,将消息输出到消息列表框中
  37. HubProxy.On<string, string>("AddMessage", (name, message) =>
  38. this.Dispatcher.Invoke(() =>
  39. RichTextBoxConsole.AppendText(String.Format("{0}: {1}\r", name, message))
  40. ));
  41.  
  42. try
  43. {
  44. await Connection.Start();
  45. }
  46. catch (HttpRequestException)
  47. {
  48. // 连接失败
  49. return;
  50. }
  51.  
  52. // 显示聊天控件
  53. ChatPanel.Visibility = Visibility.Visible;
  54. ButtonSend.IsEnabled = true;
  55. TextBoxMessage.Focus();
  56. RichTextBoxConsole.AppendText("连上服务:" + ServerUri + "\r");
  57. }

  上面的代码也就是WPF客户端实现的核心代码,主要逻辑为,客户端启动的时候就调用Connection.Start方法与服务器进行连接。然后通过HubProxy代理类来调用集线器中Send方法,而集线器中的Send方法又通过调用客户端的addMessage方法将消息输出到客户端的消息框中进行显示,从而完成消息的推送过程。接下来,让我们看看其运行效果:

  从上面的运行效果看出,其效果和Asp.net MVC上的效果是一样的。

五、总结

  到这里,本专题的所有内容就结束了,这篇SignalR快速入门也是本人在学习SignalR过程中的一些心得体会,希望可以帮助一些刚接触SignalR的朋友快速入门。本篇主要实现了SignalR的广播消息的功能,可以实现手机端消息推送的功能,接下来一篇将介绍如何使用SignalR实现一对一的聊天。

  本文所有源码:SignalR快速入门

SignalR技术的更多相关文章

  1. 在ASP.NET Core下使用SignalR技术

    一.前言 上次我们讲到过如何在ASP.NET Core中使用WebSocket,没有阅读过的朋友请参考 WebSocket in ASP.NET Core 文章 .这次的主角是SignalR它为我们提 ...

  2. 在ASP.NET CORE 2.0使用SignalR技术

    一.前言 上次讲SignalR还是在<在ASP.NET Core下使用SignalR技术>文章中提到,ASP.NET Core 1.x.x 版本发布中并没有包含SignalR技术和开发计划 ...

  3. RDIFramework.NET敏捷开发框架通过SignalR技术整合即时通讯(IM)

    1.引言 即时通讯(IM)是RDIFramework.NET敏捷开发框架全新提供的一个基于Web的即时通讯.内部聊天沟通的工具.界面美观大方对于框架内部进行消息的沟通非常方便.基于RDIFramewo ...

  4. 通过SignalR技术整合即时通讯(IM)在.NET中应用落地

    1.引言 即时通讯(IM)是RDIFramework.NET敏捷开发框架全新提供的一个基于Web的即时通讯.内部聊天沟通的工具.界面美观大方对于框架内部进行消息的沟通非常方便.基于RDIFramewo ...

  5. 用SignalR 2.0开发客服系统[系列1:实现群发通讯]

    前言 交流群:195866844 先说一下我为什么会写这个博客吧,(首先说一下,我是一个小菜鸟,讲的不好请指导 - -,)  前段时间公司的项目涉及到在B/S上使用即时通讯,(其实就是做一个B/S的客 ...

  6. ASP.NET SignalR 高可用设计

    在 One ASP.NET 的架构图中,微软将 WebAPI 和 SignalR 归类到 Services 类型与 MVC.Web Forms 同列为一等公民,未来的 ASP.NET 5 尽管还在be ...

  7. 比官方教程代码更简短的SignalR Server Broadcast示例

    SignalR是微软ASP.NET技术体系中的新成员. 在www.asp.net网站上的SignalR专区有一篇SignalR的入门级教程<Tutorial: Server Broadcast  ...

  8. [Asp.net 开发系列之SignalR篇]专题一:Asp.net SignalR快速入门

    一.前言 之前半年时间感觉自己有点浮躁,导致停顿了半年多的时间没有更新博客,今天重新开始记录博文,希望自己可以找回初心,继续沉淀.由于最近做的项目中用到SignalR技术,所以打算总结下Asp.net ...

  9. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室 实战系列(不断更新中)

    项目简介 利用ASP.NET SignalR技术与Layim前端im框架实现的一个简单的web聊天室,包括单聊,群聊,加好友,加群,好友搜索,管理,群组管理,好友权限设置等功能.涉及技术: Elast ...

随机推荐

  1. keyset与entryset

    1.基本概述 Set<Map.Entry<K,V>> entrySet()  返回此映射中包括的映射关系的 set 视图. Set<K>              ...

  2. 用 managedQuery() 时须要注意的一个陷阱

    Activity 里面提供了一个 managedQuery() 方法,依照 Android SDK 里面的说明,"the activity will manage its lifecycle ...

  3. sqlserver自学笔记之的流程控制语句

    1.使用if else语句 ①在学生表中,查找名字为王刚的同学,如果存在,显示该同学的信息,否则显示查无此人 if exists(select sno from student where sname ...

  4. Jquery事件的连接

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. flex网上办(苹果)桌面系统仿真

    1.有登录界面 2.能够载入app(每一个app是单独的swf),并可拖动app的图标互相叠加 3.桌面上显示的哪些APP与目录是依据登陆的用户信息.从webservice中读取的(名字.图标信息等) ...

  6. [Android学习笔记]捕获物理回退事件

    物理回退按钮默认情况下是finish当前activity,返回上一个activity 当需要获取物理回退按钮的相应事件时候,可以这么做 步骤如下: 1.override当前activity的onKey ...

  7. How to write simple HTTP proxy with Boost.Asio

    How to write simple HTTP proxy with Boost.Asio How to write simple HTTP proxy with Boost.Asio Russia ...

  8. STM32 + RT Thread OS 学习笔记[四]

    1.  补注 a)      硬件,打通通讯通道 若学习者购买了学习板,通常可以在学习板提供的示例代码中找到LCD的相关驱动代码,基本上,这里的驱动的所有代码都可以从里面找到. 从上面的示意图可见,M ...

  9. JavaScript实战

    JavaScript之单例实战 一.概述 所谓单例模式,顾名思义即一个类只有一个实例. 所以,当我们创建一个实例时,就必须判断其是否已经存在了这个实例,如果已经存在了这个实例,那么就返回这个已经存在的 ...

  10. ipv6加英文的中括号访问

    加英文的中括号就可以,如[2001:4998:c:e33::1004],我发现这是yahoo首页.但并不是所有IPv6网站都可以通过IPv6地址访问,跟IPv4一样,网站服务器端可以只绑定域名,不接受 ...