Create a Topshell-based application daemon (service) in C#/.NET application development

Keywords: C# Windows network Programming Database

This article is first published in: Code friend network A programming enthusiast community dedicated to. NET/.NET Core development.

Article directory

C#/.NET Creates a series of articles directory for Windows services based on Topshell:

  1. C#/.NET Creates the Installation and Unloading of Windows Service Programs and Services Based on Topshell (1)
  2. Create a Topshell-based application daemon (service) in C#/.NET application development (2)
  3. Analysis and Solution to the Problem of C#/.NET Creating a Daemon of Windows Services Based on Topshell as a Client Desktop Program Started by Services Not Displaying UI Interface (3)

Preface

In the last article "Installation and Uninstallation of Windows Service Programs and Services Based on Topshell in C#/.NET" In this article, we learn about the general process of creating Topshelf Windows service program based on C#/.NET, parameter configuration, installation and uninstallation of service. At the same time, we demonstrated the implementation of Topshell service using a simple timed task.

Today I will continue to share technical articles on Topshell. This article mainly demonstrates how to create a Topshell-based application daemon (service) in C#/.NET application development.

Create a demo application

First, open the [TopshelfDemoService.sln] solution we created earlier. In this solution, we create a client console application named TopshelfDemo.Client, which we need to guard with [TopshelfDemoService]. Just for demonstration, so the client has no practical logic and functions. In the Program.cs file, add the following sample code:

using System;

namespace TopshelfDemo.Client
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("This is a result of[Code friend network]Created ERP System sample program, currently running...");
            Console.WriteLine("Technical support: Codefriend(https://codedefautl.com) by Rector");
            Console.ReadLine();
        }
    }
}

That's it.

Once you've written it, generate or run the project. You will see a console application interface, such as:

Implementing daemon functions

Back in the project [Topshelf DemoService], open the class file HealthMonitorService.cs, where the timing function demonstrates a task to check the health of a system. Now we change the timing task function to guard one or some applications.

For the convenience of demonstration, there is no re-creation of service classes. In the actual project, you can also create different service classes according to your own situation.

Modify the code as follows:

using System;
using System.Collections.Generic;
using System.Timers;

namespace TopshelfDemoService
{
    internal class HealthMonitorService
    {
        /// <summary>
        /// Detection cycle timer
        /// </summary>
        private readonly Timer _timer;
        /// <summary>
        /// Detection cycle (seconds)
        /// </summary>
        private int _monitorInterval = 10;
        /// <summary>
        /// List of applications to guard
        /// </summary>
        private List<DaemonApplicationInfo> _daemonApps { get; set; }

        public HealthMonitorService()
        {
            // Initialize the list of applications to be guarded
            // In a real project, you can put the initialization parameters here in the configuration file / database / cache (how convenient it is)
            _daemonApps = new List<DaemonApplicationInfo> {
                new DaemonApplicationInfo {
                    ProcessName ="TopshelfDemo.Client",     // Please fill in the form according to your situation.
                    AppDisplayName ="TopshelfDemo Client", // Please fill in the form according to your situation.
                    AppFilePath =@"D:\Projects\github\TopshelfDemoService\TopshelfDemo.Client\bin\Debug\TopshelfDemo.Client.exe" // Please fill in the path here according to your actual situation.
                }
            };
            _timer = new Timer(_monitorInterval*1000) { AutoReset = true };
            _timer.Elapsed += (sender, eventArgs) => Monitor();
        }

        /// <summary>
        /// Method of daemon application
        /// </summary>
        private void Monitor()
        {
            foreach (var app in _daemonApps)
            {
                // Determine that the current process is saved and started
                if (ProcessorHelper.IsProcessExists(app.ProcessName))
                {
                    Console.WriteLine("Application[{0}] already exists.", app.ProcessName);
                    return;
                }
                try
                {
                    // If there is no process name to be guarded in the current host process list, start the corresponding application for the process
                    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();
        }
    }
}

Create new classes DaemonApplicationInfo.cs and ProcessorHelper.cs, and write the following code.

DaemonApplicationInfo.cs (application entity classes to be guarded):

namespace TopshelfDemoService
{
    /// <summary>
    /// Application entities to be guarded
    /// </summary>
    public class DaemonApplicationInfo
    {
        /// <summary>
        /// Name displayed in the process
        /// </summary>
        public string ProcessName { get; set; }
        /// <summary>
        /// Application installation path
        /// </summary>
        public string AppFilePath { get; set; }
        /// <summary>
        /// Name of application
        /// </summary>
        public string AppDisplayName { get; set; }

        /// <summary>
        /// parameter
        /// </summary>
        public string Args { get; set; }
    }
}

ProcessorHelper.cs (Process Processing Help Class):

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace TopshelfDemoService
{
    /// <summary>
    /// Process Processing Help Class
    /// </summary>
    internal class ProcessorHelper
    {
        /// <summary>
        /// Get a list (collection) of all processes on the current computer
        /// </summary>
        /// <returns></returns>
        public static List<Process> GetProcessList()
        {
            return GetProcesses().ToList();
        }

        /// <summary>
        /// Get a list (array) of all processes on the current computer
        /// </summary>
        /// <returns></returns>
        public static Process[] GetProcesses()
        {
            var processList = Process.GetProcesses();
            return processList;
        }

        /// <summary>
        /// Determine whether the specified process exists
        /// </summary>
        /// <param name="processName"></param>
        /// <returns></returns>
        public static bool IsProcessExists(string processName)
        {
            return Process.GetProcessesByName(processName).Length > 0;
        }

        /// <summary>
        /// Start an application with a specified path
        /// </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{}
        }
    }
}

After completing the above coding, we shut down the project program [TopshelfDemo.Client] and [TopshelfDemoService] first (if they are running), and then run the project [TopshelfDemoService]. Here's the moment to witness the miracle:

As you can see, the daemon [TopshelfDemoService] automatically starts the client program [TopshelfDemo.Client.exe], and only starts one client instance program. When we close the client, the next time the daemon detects, the client program will be restarted.

remaining problems

If you are happily installing TopshelfDemoService as a Windows service, you may encounter the problem that the daemon runs normally, the client program can be guarded and started normally, and the client process can be found in the Windows Task Manager, but the UI interface of the client program can not be seen.

What's the matter??? Is there something wrong??? How should we solve it????

Listen to the next decomposition (to be continued)...

Okay, that's all for today's sharing of creating a Topshell-based application daemon (service) in C#/.NET application development.

I'm Rector. I hope this article will help you with C#/.NET development.

Source code download

The hosted address of this sample code can be found in its original source: Sample Code Download Address

Posted by kcorless on Wed, 01 May 2019 23:10:38 -0700