基於SignalR實現B/S系統對windows服務運行狀態的監測

一般來說一個BS項目確定不止單獨的一個BS應用,可能涉及到不少後臺服務來支持BS的運行,特別是針對耗時較長的某些任務來講,Windows服務確定是必不可少的,咱們還須要利用B/S與windows服務進行交互,來實現更好的用戶體驗,搭配redis,memcached等來實現分佈式緩存,消息列隊處理等等。。。javascript

可是一般狀況咱們在B/S端是沒法得知其依賴的windows服務當前處於什麼樣的運行狀態,只能經過到server裏面去進行查看,或者經過其餘途徑!html

今天咱們就經過SignalR來實現一個B/S端對windows服務運行狀態的監控,這裏咱們用SignalR selfHost,不依賴IIS,而後利用topshelf把SignalR Server部署成windows服務,而後在B/S端經過SignalR js client進行鏈接獲取服務運行狀態!java

 

首先建立一個控制檯應用程序,.NET 4.5,Nuget添加 Microsoft.AspNet.SignalR.SelfHost Microsoft.Owin.Cors TopShelf(實現windows服務安裝)jquery

具體新建SignalR SelfHost Server的方法能夠看我之前的博客:SignalR SelfHost實時消息,集成到web中,實現服務器消息推送

web

新建一個hub命名爲ServiceMonitorHub,繼承Microsoft.AspNet.SignalR.Hub,咱們要實現服務狀態1秒鐘推送一次redis

具體代碼以下windows

 1 using System.Linq;
 2 using System.Threading;
 3 
 4 namespace wxRbt.Service.Realtime.Hub
 5 {
 6     /// <summary>
 7     /// 服務監控器
 8     /// </summary>
 9     public class ServiceMonitorHub:Microsoft.AspNet.SignalR.Hub
10     {
11         static ServiceMonitorHub()
12         {
13             new Thread(new ThreadStart(() =>
14             {
15                 while (true)
16                 {
17                     //獲取全部服務名稱以wxRbt開頭的服務
18                     var services = System.ServiceProcess.ServiceController.GetServices().Where(t => t.ServiceName.StartsWith("wxRbt"))
19                         .Select(t => new Model.Service
20                         {
21                             DisplayName = t.DisplayName,
22                             ServiceName = t.ServiceName,
23                             Status = (int)t.Status
24                         }).ToArray();
25                     Microsoft.AspNet.SignalR.GlobalHost.ConnectionManager.GetHubContext<ServiceMonitorHub>().Clients.All.refresh(services);
26                     //休眠一秒,實現每秒推送服務運行狀態
27                     System.Threading.Thread.Sleep(1000);
28                 }
29             })).Start();
30         }
31     }
32 }

如今咱們再利用TopShelf把當前的控制檯安裝成windows服務緩存

新建一個類ServiceMonitorService,繼承Topshelf.ServiceControl接口,實現其Start跟Stop方法,具體代碼以下服務器

 1 using Microsoft.AspNet.SignalR;
 2 using Microsoft.Owin.Cors;
 3 using Microsoft.Owin.Hosting;
 4 using Owin;
 5 using System;
 6 using Topshelf;
 7 using System.Configuration;
 8 
 9 namespace wxRbt.Service.Realtime.Service
10 {
11     public class ServiceMonitorService:ServiceControl
12     {
13         private IDisposable app;
14         private static string domain="http://*:3333";
15 
16         static ServiceMonitorService() {
17             domain = ConfigurationManager.AppSettings["Domain"] ?? domain;
18             Console.WriteLine("獲取配置:"+domain);
19         }
20 
21         public bool Start(HostControl hostControl)
22         {
23             Console.WriteLine("事實消息服務運行在:"+domain);
24             
25             app = WebApp.Start(domain, builder =>
26             {
27                 builder.UseCors(CorsOptions.AllowAll);
28                 builder.MapSignalR(new HubConfiguration
29                 {
30                     EnableJSONP = true,
31                     EnableDetailedErrors = true,
32                     EnableJavaScriptProxies = true
33                 });
34             });
35             return true;
36         }
37 
38         public bool Stop(HostControl hostControl)
39         {
40             if (app != null) {
41                 app.Dispose();
42             }
43             return true;
44         }
45     }
46 }

這裏給個默認的監聽域名,而後從app.config讀取配置的監聽域名微信

最後打開Progarm.cs文件,代碼以下:

 1 using Topshelf;
 2 
 3 
 4 namespace wxRbt.Service.Realtime
 5 {
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             HostFactory.Run(s => {
11                 s.Service<Service.ServiceMonitorService>();
12                 s.SetDisplayName("微信實時消息服務");
13                 s.StartAutomatically();
14             });
15         }
16     }
17 }

調試運行程序,如圖

 

 

上面服務端已經完成,下面,咱們來實現客戶端:

建立一個MVC4.0web空項目(隨便,我的愛好),Nuget引用Microsoft.AspNet.SignalR.JS,該js依賴jquery,會自動下載jquery,寫TypeScript同窗能夠順帶下載這兩個JS的d.ts文件

而後建立一個HomeController,在Index裏面返回view便可

Views文件夾建立Home文件夾,建立一個Index.cshtml 的razor試圖,引用jquery跟signalrjs

而後建立一個單獨的JS,儘可能不要把js寫到頁面裏面去

這裏我用TypeScript寫一個消息模塊

 1 /// <reference path="../../../scripts/typings/signalr/signalr.d.ts" />
 2 
 3 module wxrbt.manager {
 4     export const enum ServiceStatus {
 5         /**服務中止*/
 6         Stopped = 1,
 7         /**正在運行*/
 8         StartPending = 2,
 9         /**正在中止*/
10         StopPending = 3,
11         /**運行中*/
12         Running = 4,
13         /**正在繼續*/
14         ContinuePending = 5,
15         /**正在暫停*/
16         PausePending = 6,
17         /**已暫停*/
18         Paused = 7,
19     }
20     interface IService {
21         DisplayName: string;
22         ServiceName: string;
23         Status: ServiceStatus
24     }
25     /**管理服務*/
26     export class service {
27         private proxy: SignalR.Hub.Proxy;
28         private $: JQueryStatic;
29         private ip: string;
30         private port: number;
31         constructor(ip: string, port: number) {
32             this.ip = ip;
33             this.port = port;
34         }
35         /**
36          * 開啓服務運行狀態監測
37          * @param {(services} callback
38          */
39         start(callback: (services: Array<IService>) => void) {
40             jQuery.getScript("http://" + this.ip + ":" + this.port + "/signalr/hubs", () => {
41                 jQuery.connection.hub.url = "http://" + this.ip + ":" + this.port + "/signalr";
42                 this.proxy = jQuery.signalR.hub.createHubProxy("ServiceMonitorHub");
43 
44                 //每次刷新數據回調
45                 this.proxy.on("refresh", (services: Array<IService>) => {
46                     callback(services);
47                 });
48 
49 
50                 jQuery.connection.hub.start().fail(() => {
51                     alert("鏈接實時消息服務期:http://" + this.ip + ":" + this.port + "失敗,請確認消息服務配置正確且正常開啓!");
52                 });
53             });
54         }
55     }
56 }

下面我結合RequireJs實現的該模塊調用

 1 require(["message"], () => {
 2 
 3     jQuery(() => {
 4 
 5         var $service = jQuery("#serviceList");
 6         var msg = new wxrbt.manager.service("127.0.0.1", 3333);
 7         msg.start(services=>{
 8             $service.empty();
 9             for (let service of services) {
10                 var isRunning = service.Status == wxrbt.manager.ServiceStatus.Running;
11                 var statusCls = isRunning ? "success" : "warning";
12                 var statusTxt = isRunning ? "運行中" : "已中止";
13                 var status = `<label class='label label-${statusCls}'>${statusTxt}</label>`;
14                 $service.append(`<li><a href='javascript:;'><i class='icon-check'></i>${service.DisplayName}${status}</a></li><li class="divider"></li>`);
15             }
16         });
17 
18     });
19 
20 
21 });

最後運行頁面查看效果:

 

惟一不足的就是1秒鐘這個dropdownlist會閃動一次,我這裏是先清除再append進來,因此會出現這個狀況,若是採用dom節點遞歸更新狀態就不會有這個問題了!

由於是公司項目,沒辦法上源碼!有不清除的能夠留言!

下面是在windows服務器上跑的服務截圖

相關文章
相關標籤/搜索