C#Develop windows services

Keywords: Windows xml encoding Attribute

Introduction to Windows Service Application

Microsoft Windows Services (formerly known as NT Services) allow users to create executable applications that can run for a long time in their own Windows sessions.These services start automatically when the computer starts, can be paused and restarted, and do not display any user interface.These capabilities make the service ideal for use on servers or for long-running functions that do not affect other users working on the same computer.Services can also be run in the security context of a specific user account that is different from the logged-in user or the default computer account.

Services can be easily created by creating applications that are installed as services.For example, suppose you want to monitor performance counter data and respond to thresholds.You can write a Windows service application that listens to performance counter data, deploy the application, and begin collecting and analyzing data.

You can create a service as a Microsoft Visual Studio project and define code in it to control which commands can be sent to the service and what actions should be taken when they are received.Commands that can be sent to a service include starting, pausing, restoring, and stopping the service, as well as executing custom commands.

After creating and generating the application, you can install it by running the command line utility InstallUtil.exe and passing the path to the service's executable.You can then use the Service Control Manager to start, stop, pause, resume, and configure services.You can also use it in the Service node of Server Explorer or ServiceController Classes accomplish many of the same tasks.

Create a simple windows service program Dome, VS2019, win10 environment.

Code:

Service1

using System;
using System.Configuration;
using System.IO;
using System.ServiceProcess;
using System.Threading;
using System.Timers;

namespace WindowsServiceTest
{
    public partial class Service1 : ServiceBase
    {
        private string path = string.Empty;
        private string debug = string.Empty;

        /// <summary>
        ///Timer
        /// </summary>
        private static System.Timers.Timer aTimer;

        private const string strat = "Service Start";
        private const string stop = "Service Stop";
        private const string run = "Service running";
        private const string pause = "Service pausing";
        private const string conti = "Service restored";
        private const string shutdown = "Service is about to stop running";

        /// <summary>
        ///Read-write lock, when the resource is in write mode, other threads need to wait for this write to end before continuing to write
        /// </summary>
        static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();

        public Service1()
        {
            InitializeComponent();
            path = ConfigurationManager.AppSettings["PATH"];
            debug = ConfigurationManager.AppSettings["Debug"];
        }





        /// <summary>
        ///Timed Tasks
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ATimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            work(run);
        }


        private void work(string str)
        {
            try
            {
                // //Set the read/write lock to be a write mode exclusive resource. Other write requests will need to wait until the end of this write before continuing to write.
                LogWriteLock.EnterWriteLock();

                WriteTxt(path, str);
            }
            catch(Exception ex)
            {
                WriteTxt(debug, DateTime.Now.ToString()+" : "+ ex.Message);
            }
            finally
            {
                ////Exit write mode, freeing resources takes up one request for one release. If the number of releases is greater than the number of requests, an exception will be triggered [write lock is released without being held] If it is not released after request processing is complete, an exception will be triggered [this mode does not allow recursive acquisition of write locks]
                LogWriteLock.ExitWriteLock();
            }
            
        }

        /// <summary>
        ///Write text to file
        /// </summary>
        /// <param name="path">path</param>
        /// <param name="txt">text</param>
        private  void WriteTxt(string path,string txt)
        {
            if (!File.Exists(path))
            {
                File.Create(path).Close();
            }
            using (FileStream stream = new FileStream(path, FileMode.Append))
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.WriteLine($"{DateTime.Now},{txt}");
            }
        }

        #region Service Start and Stop
        /// <summary>
        ///Service Startup Execution Code
        /// </summary>
        /// <param name="args"></param>
        protected override void OnStart(string[] args)
        {

            aTimer = new System.Timers.Timer
            {
                Interval = 5000
            };
            aTimer.Elapsed += ATimer_Elapsed;
            aTimer.Enabled = true;
            aTimer.Start();
        }

        /// <summary>
        ///Service End Execution Code
        /// </summary>
        protected override void OnStop()
        {
            work(stop);
            aTimer.Enabled = false;
        }

        /// <summary>
        ///Service Suspend Code Execution
        /// </summary>
        protected override void OnPause()
        {
           
            work(pause);
            aTimer.Enabled = false;
            aTimer.Stop();
        }

        /// <summary>
        ///Service Recovery Execution Code
        /// </summary>
        protected override void OnContinue()
        {
           
            work(conti);
            aTimer.Enabled = true;
            aTimer.Start();
        }

        /// <summary>
        ///Service is closing execution code
        /// </summary>
        protected override void OnShutdown()
        {
            work(shutdown);
        }
        #endregion

        #region debugging code
        /// <summary>
        ///Service Startup Execution Code
        /// </summary>
        /// <param name="args"></param>
        internal void DebugOnStart()
        {

            aTimer = new System.Timers.Timer
            {
                Interval = 5000
            };
            aTimer.Elapsed += ATimer_Elapsed;
            aTimer.Enabled = true;
            aTimer.Start();
        }

        /// <summary>
        ///Service End Execution Code
        /// </summary>
        internal void DebugOnStop()
        {
            work(stop);
            aTimer.Enabled = false;
        }

        /// <summary>
        ///Service Suspend Code Execution
        /// </summary>
        internal void DebugOnPause()
        {

            work(pause);
            aTimer.Enabled = false;
            aTimer.Stop();
        }

        /// <summary>
        ///Service Recovery Execution Code
        /// </summary>
        internal void DebugOnContinue()
        {

            work(conti);
            aTimer.Enabled = true;
            aTimer.Start();
        }

        /// <summary>
        ///Service is closing execution code
        /// </summary>
        internal void DebugOnShutdown()
        {
            work(shutdown);
        } 
        #endregion


    }
}

Program

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;

namespace WindowsServiceTest
{
    static class Program
    {
        /// <summary>
        ///The main entry point for the application.
        /// </summary>
        static void Main()
        {
            Service1 service = new Service1();
            if (Environment.UserInteractive)//Debug mode
            {
                service.DebugOnStart();
                Console.ReadKey();
                service.DebugOnPause();
                Console.ReadKey();
                service.DebugOnContinue();
                Console.ReadKey();
                service.DebugOnShutdown();
                Console.ReadKey();
                service.DebugOnStop();
                Console.ReadKey();

            }
            else//normal
            {
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[]
                {
                    service
                };
                ServiceBase.Run(ServicesToRun);
            }

        }
    }
}

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="PATH" value="D:\\MyServiceLog.txt"/>
    <add key="Debug" value="D:\\Service\\Debug.txt"/>
  </appSettings>
</configuration>

Add Installation to Service, Add Installer on Service1.cs [Design] Interface, Right Click - "

After successful addition: the software generates two components, serviceInstaller1 and serviceProcessInstaller1.

Its properties can be modified.F4 View Properties and Modify

ServiceProcessInstaller class And ServiceInstaller class Details.

Modify attribute field values:

 

 

 

A simple debugging method that changes the project output type to the console application type.You can debug like a console program.

Installation method:

1: Use the VS developer command line

Open the VS development command line and run with administrator privileges

Instautil.exe command: +Program path (successful executable path generated)

My name is: E:\CNotes\WindowsService\WindowsServiceTest\binDebug\WindowsServiceTest.exe

View service:

Uninstall service:

installutil.exe/u E:\C#Notes\WindowsService\WindowsServiceTest\bin\Debug\WindowsServiceTest.exe

If the service does not terminate, use the CMD command to force kill.Open a command line window, run the sc queryex command to get the PID of the service, then use the taskkill command to stop it

Force deletion of service:

sc delete service name (if there is a space in the service name, quotation marks are required); then restart your computer services.msc to open the list of services should disappear.

 

Install services using the program interface:

Create a new winform program that references the server service.

Code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.ServiceProcess;
using System.Configuration.Install;
using System.Configuration;
using System.Collections;

namespace ServiceSetup
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            serviceFilePath = ConfigurationManager.AppSettings["PATH"];
        }

        string serviceFilePath = string.Empty;
        string serviceName = "MyService";

        /// <summary>
        ///Install Services
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void butSetup_Click(object sender, EventArgs e)
        {
            if (this.IsServiceExisted(serviceName))
            {
                this.UninstallService(serviceName);
            } 
            this.InstallService(serviceFilePath);

        }

        /// <summary>
        ///Start the service
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void butStrat_Click(object sender, EventArgs e)
        {
            if (this.IsServiceExisted(serviceName))
            {
                this.ServiceStart(serviceName);
            }
            else
            {
                MessageBox.Show("Service does not exist!");
            }
               
        }

        /// <summary>
        ///Stop Service
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void butStop_Click(object sender, EventArgs e)
        {
            if (this.IsServiceExisted(serviceName))
            {
                this.ServiceStop(serviceName);
            }
               
        }

        /// <summary>
        ///Uninstall Service
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void butUninstall_Click(object sender, EventArgs e)
        {
            if (this.IsServiceExisted(serviceName))
            {
                this.ServiceStop(serviceName);
                this.UninstallService(serviceFilePath);
            }
        }

        /// <summary>
        ///Determine if the service exists
        /// </summary>
        /// <param name="serviceName">service name</param>
        /// <returns></returns>
        private bool IsServiceExisted(string serviceName)
        {
            ServiceController[] services = ServiceController.GetServices();
            foreach (ServiceController sc in services)
            {
                if (sc.ServiceName.ToLower() == serviceName.ToLower())
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        ///Install Services
        /// </summary>
        /// <param name="serviceFilePath"></param>
        private void InstallService(string serviceFilePath)
        {
            using (AssemblyInstaller installer = new AssemblyInstaller())
            {
                installer.UseNewContext = true;
                installer.Path = serviceFilePath;
                IDictionary savedState = new Hashtable();
                installer.Install(savedState);
                installer.Commit(savedState);
            }
        }

        /// <summary>
        ///Uninstall Service
        /// </summary>
        /// <param name="serviceFilePath"></param>
        private void UninstallService(string serviceFilePath)
        {
            using (AssemblyInstaller installer = new AssemblyInstaller())
            {
                installer.UseNewContext = true;
                installer.Path = serviceFilePath;
                installer.Uninstall(null);
            }
        }

        /// <summary>
        ///Start the service
        /// </summary>
        /// <param name="serviceName"></param>
        private void ServiceStart(string serviceName)
        {
            using (ServiceController control = new ServiceController(serviceName))
            {
                if (control.Status == ServiceControllerStatus.Stopped)
                {
                    control.Start();
                }
            }
        }

        /// <summary>
        ///Stop Service
        /// </summary>
        /// <param name="serviceName"></param>
        private void ServiceStop(string serviceName)
        {
            using (ServiceController control = new ServiceController(serviceName))
            {
                if (control.Status == ServiceControllerStatus.Running)
                {
                    control.Stop();
                }
            }
        }


    }
}

However, starting the installation must run with administrator privileges in order to install the service

Program

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ServiceSetup
{
    static class Program
    {
        /// <summary>
        ///The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //Get the Windows user ID for the current login
            System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
            System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity);
            //Determine if the current user is an administrator privilege
            if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator))
            {
                Application.Run(new MainForm()); //Is an administrator.Direct Run
            }
            else
            {
                //Create Startup Object
                System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
                startInfo.UseShellExecute = true;
                startInfo.WorkingDirectory = Environment.CurrentDirectory;
                startInfo.FileName = Application.ExecutablePath;
                //Set up startup actions to ensure that you run as an administrator
                startInfo.Verb = "runas";
                try
                {
                    System.Diagnostics.Process.Start(startInfo);
                }
                catch
                {
                    return;
                }
                Application.Exit();
            }
                
        }
    }
}

Reference Blog: https://blog.csdn.net/Andrewniu/article/details/97300245

 

Published 91 original articles, won 13. Visited 20,000+
Private letter follow

Posted by jrbilodeau on Sat, 29 Feb 2020 19:48:13 -0800