C# Getting Started with Windows Service Development

Posted by jamesl73 on Fri, 15 May 2020 05:49:48 +0200

1. Conceptual Name

Windows services (formerly NT services) allow you to create executable applications that run for a long time in their own Windows sessions.These services can be automatically started at computer startup, paused and restarted, and do not display any user interface.This service is ideal for use on servers or at any time when long-running functionality is required in order not to affect other users working on the same computer.

2. Creating Windows Services

2.1. Create Project

New->Project->Windows Desktop->Windows Service.

The project right-click property - > Application - > Output type, you can see that it belongs to "Windows Application".

2.2. Add Installer

Open Service1.cs->Right-click in the blank->Add Installer.

2.3. Set up installation information

Open ProjectInstaller.cs.

    2.3.1,serviceInstaller1

Click serviceInstaller1 to set the service information in the properties, for example, to create a "HelloWorld" service.

Explain:

Description: The description of the service, which is displayed directly in the list of Windows services.

DisplayName: The name of the service display, which is displayed directly in the list of Windows services.

ServiceName: The name of the service, the identity when the service is started or stopped.

StartType: Start type, such as automatic, manual, etc.

    2.3.2,serviceProcessInstaller1

Click serviceProcessInstaller1 to set the account type that runs the service in the properties.

2.4. Build Project

Considering the Debugger debugging method that will be discussed later, select Release mode here to generate.

3. Installation and uninstallation services

    3.1,InstallUtil.exe

Copy InstallUtil.exe to the Release folder of the project in the VS installation directory. The path for InstallUtil.exe in VS2017 is: C:\Windows\Microsoft.NETFrameworkv4.0.309.

3.2. Installation Services

Enter "cmd" in the address bar of the Release folder to bring up the command prompt form:

Install service command:

InstallUtil.exe LinkTo.Test.WindowsService.exe

Start service command:

net start HelloWorld

Of course, generally we use batch processing to install and uninstall services.

Under the Release folder, create a batch file for Install Services.bat:

@echo off
echo===================================================
echo      LinkTo.Test.WindowsService Installing services
echo===================================================

@echo off
InstallUtil.exe LinkTo.Test.WindowsService.exe

@echo off
echo===================================================
echo      LinkTo.Test.WindowsService Starting service
echo===================================================

@echo off
net start HelloWorld

pause

Enter "at run time"services.msc"When you enter the service, you will see the new HelloWorld service:

*3.3, Uninstall Services

Under the Release folder, create a batch file for "Uninstall Service.bat":

@echo off
echo===================================================
echo      LinkTo.Test.WindowsService Stopping service
echo===================================================

@echo off
net stop HelloWorld

@echo off
echo===================================================
echo      LinkTo.Test.WindowsService Uninstalling services
echo===================================================

@echo off
InstallUtil.exe /u LinkTo.Test.WindowsService.exe

pause

4. Service Timer

In general, the service sets how often a task is executed, which is used here System.Threading.Timer For a simple logging, write the log to the Release\Log folder.

    public partial class Service1 : ServiceBase
    {
        private static Timer timerAsync = null;
        private int dueTimeInterval = 1000 * 5; //Unit: milliseconds
        private int periodInterval = 1000 * 5;  //Unit: milliseconds

        public Service1()
        {
            InitializeComponent();
            //callback: One TimerCallback Delegate, indicating the method to be executed.
            //state: An object containing information to be used by the callback method, or an empty reference.
            //dueTime: call callback The amount of time delayed before (in milliseconds).Appoint Timeout.Infinite To prevent the timer from starting to time, specify zero(0)To start the timer immediately.
            //period: call callback Time interval in milliseconds.Appoint Timeout.Infinite Periodic termination can be disabled.
            timerAsync = new Timer(AutoAsyncCallback, null, Timeout.Infinite, Timeout.Infinite);
        }

        /// <summary>
        /// Service Start
        /// </summary>
        /// <param name="args"></param>
        protected override void OnStart(string[] args)
        {
            base.OnStart(args);
            timerAsync.Change(dueTimeInterval, periodInterval); ;
            WriteLog(DateTime.Now.ToString("HH:mm:ss") + " Service Start" + "\r\n");
            WriteLog(Environment.NewLine);
        }

        /// <summary>
        /// Service Stop
        /// </summary>
        protected override void OnStop()
        {
            base.OnStop();
            if (timerAsync != null)
            {
                timerAsync.Change(Timeout.Infinite, Timeout.Infinite);
                timerAsync.Dispose();
                timerAsync = null;
            }
            WriteLog(DateTime.Now.ToString("HH:mm:ss") + " Service Stop" + "\r\n");
            WriteLog(Environment.NewLine);
        }

        /// <summary>
        /// Service pause
        /// </summary>
        protected override void OnPause()
        {
            base.OnPause();
            WriteLog(DateTime.Now.ToString("HH:mm:ss") + " Service pause" + "\r\n");
            WriteLog(Environment.NewLine);
        }

        /// <summary>
        /// Computer shutdown
        /// </summary>
        protected override void OnShutdown()
        {
            base.OnShutdown();
            WriteLog(DateTime.Now.ToString("HH:mm:ss") + " Computer shutdown" + "\r\n");
            WriteLog(Environment.NewLine);
        }

        /// <summary>
        /// callback
        /// </summary>
        /// <param name="state"></param>
        private void AutoAsyncCallback(object state)
        {
            try
            {
                timerAsync.Change(Timeout.Infinite, Timeout.Infinite);
#if DEBUG
                if (!Debugger.IsAttached)
                    Debugger.Launch();      //When the process runs here, it stops automatically and pops up a prompt box
                Debugger.Break();           //This method and the VS The breakpoint with red added to is identical
#endif
                WriteLog(DateTime.Now.ToString("HH:mm:ss") + " AutoAsyncCallback Execution Starts, Threads ID = " + Thread.CurrentThread.ManagedThreadId + "\r\n");
                Thread.Sleep(1000 * 10);    //The simulation takes longer to compute and takes longer than the timed interval.
            }
            catch (Exception ex)
            {
                WriteLog(DateTime.Now.ToString("HH:mm:ss") + " AutoAsyncCallback Execution Exception:" + "\r\n" + ex.Message);
            }
            finally
            {
                timerAsync.Change(dueTimeInterval, periodInterval);
                WriteLog(DateTime.Now.ToString("HH:mm:ss") + " AutoAsyncCallback end of execution" + "\r\n");
                WriteLog(Environment.NewLine);
            }
        }

        /// <summary>
        /// Logging
        /// </summary>
        /// <param name="logInfo">log information</param>
        void WriteLog(string logInfo)
        {
            try
            {
                string logDirectory = AppDomain.CurrentDomain.BaseDirectory + "\\Log";
                if (!Directory.Exists(logDirectory))
                {
                    Directory.CreateDirectory(logDirectory);
                }
                string filePath = logDirectory + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                File.AppendAllText(filePath, logInfo);
            }
            catch
            { }
        }
    }
Service1.cs

5. Debugging Services

Because the Windows service program cannot be executed directly, it cannot be directly interrupted for debugging.There are two common ways to debug a service:

*5.1, attach to process

After the service starts, click Debug->Attach to Process->SelectLinkTo.Test.WindowsService->Additional.

    5.2,Debugger

#if DEBUG
                if (!Debugger.IsAttached)
                    Debugger.Launch();      //When the process runs here, it stops automatically and pops up a prompt box
                Debugger.Break();           //This method and the VS The breakpoint with red added to is identical
#endif

For debugging using Debugger code, Release mode is required when the project is generated, or there will always be additional prompts to modify the Release mode in the Configuration Manager.(

Topics: C# Windows