zoukankan      html  css  js  c++  java
  • 在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务)

    本文首发于:码友网--一个专注.NET/.NET Core开发的编程爱好者社区。

    文章目录

    C#/.NET基于Topshelf创建Windows服务的系列文章目录:

    1. C#/.NET基于Topshelf创建Windows服务程序及服务的安装和卸载 (1)
    2. 在C#/.NET应用程序开发中创建一个基于Topshelf的应用程序守护进程(服务) (2)
    3. 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:ProjectsgithubTopshelfDemoServiceTopshelfDemo.ClientinDebugTopshelfDemo.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.csProcessorHelper.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开发的你有所帮助。

    源代码下载

    本示例代码托管地址可以在原出处找到:示例代码下载地址

  • 相关阅读:
    视频:JDBCRDD源码及自定义JDBCRDD的分区策略
    聊聊spark-submit的几个有用选项
    线性求第k大
    汇编基础 第一章_总线
    长度不超过n的连续最大和___优先队列
    ISAP
    次小生成树
    k短路
    求出欧拉回路,欧拉路径
    拓扑排序bfs_dfs
  • 原文地址:https://www.cnblogs.com/bobositlife/p/create-daemon-service-with-topshelf-in-csharp-application.html
Copyright © 2011-2022 走看看