在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务)

本文首发于:码友网–一个专注.NET/.NET Core开发的编程爱好者社区。文章目录C#/.NET基于Topshelf创建Windows服务的系列文章目录:C#/.NET基于Topshelf创建Windows服务程序及服务的安装和卸载 (1)在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务) (2)C#/.NET基于Topshelf创建Windows服务的守护程序作为服务启动的客户端桌面程序不显示UI界面的问题分析和解决方案 (3)前言在上一篇文章《C#/.NET基于Topshelf创建Windows服务程序及服务的安装和卸载》中,我们了解发C#/.NET创建基于Topshelf Windows服务程序的大致流程,参数配置以及服务的安装和卸载。同时,我们也使用一个简单的定时任务演示了Topshelf服务的执行情况。今天我将继续为大家分享关于Topshelf主题的技术文章。本文主要演示在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务)。创建一个演示应用程序首先,打开之前我们创建的[TopshelfDemoService.sln]解决方案。在这个解决方案中再创建一个名为TopshelfDemo.Client的客户端控制台应用程序,这个客户端程序即是我们需要使用[TopshelfDemoService]守护的。只是为了演示,所以客户端并没有实际意义的逻辑和功能,在Program.cs文件中,添加如下示例代码:using System;namespace TopshelfDemo.Client{ class Program { static void Main(string[] args) { Console.WriteLine(“这是一个由[码友网]创建的ERP系统示例程序,目前正在运行…”); Console.WriteLine(“技术支持:码友网(https://codedefautl.com) by Rector”); Console.ReadLine(); } }}仅此而已。编写好后,生成或者运行一下这个项目。你会看到一个控制台应用程序界面,如:实现守护程序功能再回到项目[TopshelfDemoService]中,打开类文件HealthMonitorService.cs,其中的定时功能演示的是一个检查某系统健康状况的任务,现在我们把定时任务功能改为守护某个或者某些应用程序。这里为了演示方便,没有重新创建服务类,在实际项目中,你也可以根据自己的情况创建不同的服务类。修改其中代码为如下所示:using System;using System.Collections.Generic;using System.Timers;namespace TopshelfDemoService{ internal class HealthMonitorService { /// <summary> /// 检测周期计时器 /// </summary> private readonly Timer _timer; /// <summary> /// 检测周期(秒) /// </summary> private int _monitorInterval = 10; /// <summary> /// 要守护的应用程序列表 /// </summary> private List<DaemonApplicationInfo> _daemonApps { get; set; } public HealthMonitorService() { // 初始化要守护的应用程序列表 // 实际项目中,你可以将这里的初始化参数放到配置文件/数据库/缓存中(怎么方便怎么来) _daemonApps = new List<DaemonApplicationInfo> { new DaemonApplicationInfo { ProcessName =“TopshelfDemo.Client”, // 请根据你的情况填写 AppDisplayName =“TopshelfDemo Client”, // 请根据你的情况填写 AppFilePath =@“D:\Projects\github\TopshelfDemoService\TopshelfDemo.Client\bin\Debug\TopshelfDemo.Client.exe” // 这里的路径请根据你的实际情况填写 } }; _timer = new Timer(_monitorInterval*1000) { AutoReset = true }; _timer.Elapsed += (sender, eventArgs) => Monitor(); } /// <summary> /// 守护应用程序的方法 /// </summary> private void Monitor() { foreach (var app in _daemonApps) { // 判断当前进程是存已启动 if (ProcessorHelper.IsProcessExists(app.ProcessName)) { Console.WriteLine(“Application[{0}] already exists.”, app.ProcessName); return; } try { // 当前主机进程列表中没有需要守护的进程名称,则启动这个进程对应的应用程序 ProcessorHelper.RunProcess(app.AppFilePath, app.Args); } catch (Exception ex) { Console.WriteLine(“Start application failed:{0}”, ex); } } } public void Start() { _timer.Start(); } public void Stop() { _timer.Stop(); } }}新建类DaemonApplicationInfo.cs和ProcessorHelper.cs,编写如下代码。DaemonApplicationInfo.cs(需守护的应用程序实体类):namespace TopshelfDemoService{ /// <summary> /// 需守护的应用程序实体 /// </summary> public class DaemonApplicationInfo { /// <summary> /// 进程中显示的名称 /// </summary> public string ProcessName { get; set; } /// <summary> /// 应用程序安装路径 /// </summary> public string AppFilePath { get; set; } /// <summary> /// 应用程序的名称 /// </summary> public string AppDisplayName { get; set; } /// <summary> /// 参数 /// </summary> public string Args { get; set; } }}ProcessorHelper.cs(进程处理帮助类):using System.Collections.Generic;using System.Diagnostics;using System.Linq;namespace TopshelfDemoService{ /// <summary> /// 进程处理帮助类 /// </summary> internal class ProcessorHelper { /// <summary> /// 获取当前计算机所有的进程列表(集合) /// </summary> /// <returns></returns> public static List<Process> GetProcessList() { return GetProcesses().ToList(); } /// <summary> /// 获取当前计算机所有的进程列表(数组) /// </summary> /// <returns></returns> public static Process[] GetProcesses() { var processList = Process.GetProcesses(); return processList; } /// <summary> /// 判断指定的进程是否存在 /// </summary> /// <param name=“processName”></param> /// <returns></returns> public static bool IsProcessExists(string processName) { return Process.GetProcessesByName(processName).Length > 0; } /// <summary> /// 启动一个指定路径的应用程序 /// </summary> /// <param name=“applicationPath”></param> /// <param name=“args”></param> public static void RunProcess(string applicationPath, string args = “”) { try { var psi = new ProcessStartInfo { FileName = applicationPath, WindowStyle = ProcessWindowStyle.Normal, Arguments = args }; Process.Start(psi); } catch{} } }}完成以上编码后,我们将项目程序[TopshelfDemo.Client]和[TopshelfDemoService]先都关闭掉(如果已运行),接着运行项目[TopshelfDemoService],下面就是见证奇迹的时刻啦:可以看到,守护程序[TopshelfDemoService]自动启动了客户端程序[TopshelfDemo.Client.exe],并且只会启动一个客户端实例程序。当我们把客户端关闭后,下次守护程序检测的时候客户端程序又会被重启。遗留问题如果你正高高兴兴地将TopshelfDemoService作为Windows服务安装,那么你可能会遇到这个问题,即守护进程正常运行,客户端程序也能正常地被守护并且启动,在Windows的"任务管理器"中也可以找到客户端的进程,但却看不到客户端程序的UI界面。这是怎么回事呢???是不是哪里出错了呢???应该如何解决呢???预知后事如何请听下回分解(未完待续)…好了,今天的在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务)的分享就到这里。我是Rector,希望本文对C#/.NET开发的你有所帮助。源代码下载本示例代码托管地址可以在原出处找到:示例代码下载地址 ...

April 17, 2019 · 2 min · jiezi

C#/.NET基于Topshelf创建Windows服务程序及服务的安装和卸载

本文首发于码友网–一个专注.NET/.NET Core开发的编程爱好者社区。文章目录C#/.NET基于Topshelf创建Windows服务的系列文章目录:C#/.NET基于Topshelf创建Windows服务程序及服务的安装和卸载 (1)在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务) (2)C#/.NET基于Topshelf创建Windows服务的守护程序作为服务启动的客户端桌面程序不显示UI界面的问题分析和解决方案 (3)前言对于使用Windows操作系统的人来说,Windows Service(Windows服务)应该不会陌生。在Windows操作系统中,我们可以在"运行"窗口中运行service.msc:即可打开一个查看Windows服务的窗口,如图:Windows服务基本都是一些后台运行的服务进程,没有UI界面,每个服务处理着各自独立的任务并且有专门的启动或者停止策略。所以,Windows服务在很多情况下会被用来者处理一些定时任务或者调度。那么,对于.NET的开发者来说,可不可以自己创建Windows服务呢,如何使用C#创建Windows服务呢?本文就为大家分享一种基于Topshelf创建的Windows服务的方法。创建Topshelf服务项目首先打开Visual Studio(本文使用的是Visual Studio 2019),打开新建项目的对话框,选择.NET Framework的控制台应用程序(Console App(.NET Framework)),如图:注:只可选择控制台应用程序点击"下一步",在项目名称中输入TopshelfDemoService,.NET Framework 选择4.6.2,其中选项根据自己情况填写即可,最后点击"创建"按钮。安装Topshelf组件在TopshelfDemoService项目中,打开Nuget包管理工具,搜索Topshelf,在搜索结果中选中Topshelf,点击"安装",如图:编写Topshelf服务的示例程序代码Topshelf组件安装完成后,我们就可以开始编写服务的示例代码了。首先,创建一个名为HealthMonitorService.cs的类(其作用假设为定时监控某个系统的运行健康状况),在其中分别创建方法:Start()和Stop()以及一个定时器,让定时器定时执行检查系统健康状况的任务(这里模拟的每秒向控制台输出一条文本信息),完整的代码如下:using System;using System.Timers;namespace TopshelfDemoService{ internal class HealthMonitorService { private readonly Timer _timer; public HealthMonitorService() { _timer = new Timer(1000) { AutoReset = true }; _timer.Elapsed += (sender, eventArgs) => Console.WriteLine(“执行系统健康检查任务,所有指标均正常。执行时间:{0}”, DateTime.Now); } public void Start() { _timer.Start(); } public void Stop() { _timer.Stop(); } }}再创建一个名为MyServiceConfigure.cs的服务配置类,这个类主要用来配置Topshelf服务的各种运行参数,代码如下:using System;using Topshelf;namespace TopshelfDemoService{ internal class MyServiceConfigure { internal static void Configure() { var rc = HostFactory.Run(host => // 1 { host.Service<HealthMonitorService>(service => // 2 { service.ConstructUsing(() => new HealthMonitorService()); // 3 service.WhenStarted(s => s.Start()); // 4 service.WhenStopped(s => s.Stop()); // 5 }); host.RunAsLocalSystem(); // 6 host.EnableServiceRecovery(service => // 7 { service.RestartService(3); // 8 }); host.SetDescription(“Windows service based on topshelf”); // 9 host.SetDisplayName(“Topshelf demo service”); // 10 host.SetServiceName(“TopshelfDemoService”); // 11 host.StartAutomaticallyDelayed(); // 12 }); var exitCode = (int)Convert.ChangeType(rc, rc.GetTypeCode()); // 13 Environment.ExitCode = exitCode; } }}注:其中数字的含义请见本文末尾的解释。最后,打开Program.cs文件,开启Topshelf服务,如下:namespace TopshelfDemoService{ class Program { static void Main(string[] args) { MyServiceConfigure.Configure(); } }}好了,完成到这里,整个示例程序就写好了,按F5运行示例程序,你将看到如下类似的控制台信息:可以看到,我们创建的TopshelfDemoService服务每秒向控制台打印了一条文本信息,这和我们的预期是吻合的。这样,我们就成功创建了一个基于Topshelf的Windows服务,当然,这也只是一个简单和示例服务程序,其中没有复杂的业务逻辑和配置等等。这些都等待你去发掘。作为Windows服务安装和卸载我们刚才运行的只是一个控制台应用程序,如果将这个控制台应用程序关掉,定时任务也会被停止了。如果我们希望定时任务可以一直运行,那需要将这个控制台应用程序作为服务安装到Windows服务进程中,如何操作呢?非常简单的安装和卸载命令。首先,以管理员身份打开一个命令行工具,进入到控制台应用程序所在目录。安装安装服务运行如下命令:TopshelfDemoService.exe install打开Windows服务查看窗口(刷新),可以看到Topshelf demo service已经在服务列表中了,如图:这时,我们只需要按照Windows服务来操作这个服务即可。卸载如果需要卸载服务,则运行如下命令:TopshelfDemoService.exe uninstallTopshelf配置参数说明1.设置服务主机使用HostFactory.Run()来创建并运行一个Topshelft服务。2.设置Topshelf使用类型HealthMonitorService作为服务类。3.配置如何创建一个服务的实例,这里采用的是使用关键字new来实例化一个HealthMonitorService对象,你也可以使用IoCp容器来实例化服务对象。4.设置当服务启动时执行的操作。5.设置当服务停止时执行的操作。6.设置将服务以本地系统身份运行。7.启动恢复服务模式(当服务意外停止后自动恢复)。8.设置第一次自动恢复服务的延迟时间为3分钟。9.设置Topshelf服务在Windows服务中的描述信息。10.设置Topshelf服务在Windows服务中的显示名称。11.设置Topshelf服务在Windows服务中的服务名称。12.设置Topshelf服务随Windows启动时自动运行(延迟)。13.设置服务的退出代码。示例代码托管和下载本示例代码托管地址可以在原出处找到:示例代码下载地址 ...

April 12, 2019 · 1 min · jiezi