最近在做和以前同学做一个接的网站,因为有个需求,就是需要在某个数据库表里面插入一条信息的时候,我们需要把这条消息推送给所有的订阅这条消息的用户知道,我因为原来没有做过有关服务器主动消息推送的项目(PS:最初毕业那会是直接用ajax不断定时去获取数据库里面的记录来更新客户端的UI), 所以瞬间有点泪奔的感觉, 不过总是要硬着头皮上的哇,一头雾水,开始在网上一顿搜,网上倒是有不少解决方案, 例如使用Html的websocket协议直接开干,不过用户那边的浏览器不同意,可能不大适应直接这样做的节奏. 因为以前在微软做过小小的技术support, 所以自己还是想起来重拾SignaIR, 我的思路就是每次在在新增信息模块将消息存入一个队列,我自己在后台运行一个windows service, 每个固定时间去消息队列里面去获取最新插入的记录实体对象,如果有记录,那么我们通过Hub去推送到客户端,然后清除这个消息。这里的代码真的要感谢 汤国臣,我的大部分基本受这位大神的启发, 后面我会贴上相关的这位大神的链接参考. 废话不多说,进入正题。我不喜欢说太多,凡事都是例子为主吧, 写了个小例子. 源代码要的哈告诉我.
首先创建一个控制台应用程序,Nuget添加 Microsoft.AspNet.SignalR.SelfHost Microsoft.Owin.Cors TopShelf(实现windows服务安装),新建一个hub命名为ServiceMonitorHub,继承Microsoft.AspNet.SignalR.Hub,我们要实现服务状态3秒钟推送一次. 其实我自己项目里面是自己监测消息队列里面有没有最新的记录,如果有取出来推送,但是考虑到实际的每个人的需求不一样,这里我就每隔三秒钟去推送一次.
using Microsoft.AspNet.SignalR; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace RealtimeService { /// <summary> /// 服务监控器 /// </summary> public class ServiceMonitorHub : Hub { static ServiceMonitorHub() { new Thread(new ThreadStart(() => { while (true) { GlobalHost.ConnectionManager.GetHubContext<ServiceMonitorHub>().Clients.All.sendMessage(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), "Kelin zhang"); //休眠3秒,实现每秒推送服务运行状态 System.Threading.Thread.Sleep(3000); } })).Start(); } } }
新建一个类ServiceMonitorService,继承Topshelf.ServiceControl接口,实现其Start跟Stop方法,具体代码如下:
using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Text; using System.Threading.Tasks; using Topshelf; using Owin; using Microsoft.Owin; using Microsoft.Owin.Hosting; using Microsoft.Owin.Host.HttpListener; using Microsoft.Owin.Cors; using Microsoft.AspNet.SignalR; namespace RealtimeService { public class ServiceMonitorService : ServiceControl { private IDisposable app; private static string domain = "http://192.168.10.89:3333"; //你自己的IP地址服务 static ServiceMonitorService() { domain = ConfigurationManager.AppSettings["Domain"] ?? domain; Console.WriteLine("获取配置:" + domain); } public bool Start(HostControl hostControl) { Console.WriteLine("事实消息服务运行在:" + domain); app = WebApp.Start(domain, builder => { builder.UseCors(CorsOptions.AllowAll); builder.MapSignalR(new HubConfiguration { EnableJSONP = true, EnableDetailedErrors = true, EnableJavaScriptProxies = true }); }); return true; } public bool Stop(HostControl hostControl) { if (app != null) { app.Dispose(); } return true; } } }
最后打开Progarm.cs文件,代码如下:
using System; using Topshelf; namespace RealtimeService { class Program { static void Main(string[] args) { HostFactory.Run(s => { s.Service<ServiceMonitorService>(); s.SetDisplayName("实时消息服务"); s.StartAutomatically(); }); Console.ReadKey(); } } }
然后我们直接运行这个控制台程序,就可以看到如下页面:
为了注册这个服务到系统里面, 用管理员权限打开cmd, 然后进行注册吧! 如果你不会,可以参考下面的链接:
http://www.cnblogs.com/jys509/p/4614975.html
基本上服务端就这样Happy的完成了, 我们开启这个服务,然后呢我们新建一个空的MVC的web项目.在Home控制器里面的Index的cshtml里面加上下面的代码:
@{ ViewBag.title = "SignaIR"; } <div class="container"> <ul id="messageBox"></ul> </div> @section scripts { <script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script> <script src="http://192.168.10.89:3333/signalr/hubs"></script> <script> $(function () { $.connection.hub.url = "http://192.168.10.89:3333/signalr"; //引用自动生成的集线器代理 var chat = $.signalR.hub.createHubProxy("ServiceMonitorHub"); // var chat = $.connection.ServiceMonitorHub; //定义服务器调用的客户端sendMessage来显示新消息 chat.client.sendMessage = function (name, message) { //向页面添加消息 $("#messageBox").append('<li><strong style="color:green">'+htmlEncode(name)+'</strong>:'+htmlEncode(message)+'</li>'); } //开始连接服务器 $.connection.hub.start().done(function () { }) }); //为显示的消息进行html编码 function htmlEncode(value) { var encodeValue = $('<div/>').text(value).html(); return encodeValue; } </script> }
运行吧骚年,最终你就可以Happy的看看效果图了.
希望对大家有点帮助,在做服务端消息推送的时候.
最后附上我这次搞这个功能设计参考的引用资料,智慧来自他们.