Service F9 BreakPoint Debuging

patrick

Well-known member
Joined
Dec 5, 2021
Messages
251
Programming Experience
1-3
Hello

F9 Breakpoint debugging does not work..

Service registration was completed normally.
The service was successfully registered using installutil.exe.
The scheduler also works normally.


But F9 Breakpoint ->F10 debugging does not work..

삭제2.png
 
That is because you are trying to debug by pressing F10 to start the process.

To debug a service, you need to let Windows run the service, and then in Visual Studio you use "Debug>Attach to process" and attach to the running service.

If this sounds really inconvenient, it is. This is why a lot of people who write Windows services rely extensively on unit tests. And then when unit tests are not enough, they will either:
  • Write their service as a console an app primarily, and just give it the service entry points that Windows needs; OR
  • Write almost all of their service code in a DLL, and have a console app stub and a service stub that loads that DLL. The console app stub is for debugging, while the service stub has the entry points that Windows needs.
 
Here's an example of an app that I wrote that can be debugged via the Console and then installed as a Windows service:
C#:
using NSWHealth.DX.Common;
using SI.Moh.Phisco_Periph.Dto.Mapping;
using System.IO;
using System.Linq;
using System.ServiceProcess;

namespace SI.Moh.Periph.Submissions.Service
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main(string[] args)
        {
            DomainMapper.MapDomain();

            if (args.Length == 1 && args[0] == "/console")
            {
                // Run the application as a Console app.
                using (var processor = new SubmissionProcessor())
                {
                    var folderPath = Config.GetSetting("SubmissionsRootFolder");
                    var folder = new DirectoryInfo(folderPath);
                    var searchPattern = Config.GetSetting("SubmissionFileNamePattern");

                    foreach (var file in folder.GetFiles(searchPattern).OrderBy(fi => fi.CreationTime))
                    {
                        processor.EnqueueFile(file.FullName);
                    }

                    processor.ProcessQueuedFiles();
                }
            }
            else
            {
                // Run the application as a Windows service.
                var servicesToRun = new ServiceBase[]
                {
                    new SubmissionService()
                };

                ServiceBase.Run(servicesToRun);
            }
        }
    }
}
C#:
using NSWHealth.DX.Common;
using System;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using ApplicationLogger = SI.Moh.Phisco_Periph.Global.ApplicationLogger;

namespace SI.Moh.Periph.Submissions.Service
{
    public partial class SubmissionService : ServiceBase
    {
        private const string ERROR_LOG_NAME = "PeriphErrorLog";
        private const string INFO_LOG_NAME = "PeriphInfoLog";

        private SubmissionProcessor processor;

        public SubmissionService()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            try
            {
                processor = new SubmissionProcessor();

                var folderPath = Config.GetSetting("SubmissionsRootFolder");
                var folder = new DirectoryInfo(folderPath);
                var searchPattern = Config.GetSetting("SubmissionFileNamePattern");

                ApplicationLogger.Inst.LogInfo(INFO_LOG_NAME, "Start monitoring: " + Path.Combine(folderPath, searchPattern));

                // Process files already in the submission folder.
                foreach (var file in folder.GetFiles(searchPattern).OrderBy(fi => fi.CreationTime))
                {
                    processor.EnqueueFile(file.FullName);
                }

                processor.ProcessQueuedFilesAsync();

                // Watch for new files in the submission folder.
                submissionFolderWatcher.Path = folderPath;
                submissionFolderWatcher.Filter = searchPattern;
                submissionFolderWatcher.EnableRaisingEvents = true;
            }
            catch (Exception ex)
            {
                ApplicationLogger.Inst.LogException(ERROR_LOG_NAME, ex.Message, ex);
            }
        }

        protected override void OnStop()
        {
            ApplicationLogger.Inst.LogInfo(INFO_LOG_NAME, "Stop monitoring");
        }

        private void submissionFolderWatcher_Renamed(object sender, RenamedEventArgs e)
        {
            ApplicationLogger.Inst.LogInfo(INFO_LOG_NAME, "File detected: " + e.FullPath);

            processor.EnqueueFile(e.FullPath);
            processor.ProcessQueuedFilesAsync();
        }
    }
}
The primary point to note is that the Main method looks for a particular argument and runs as a Console app if it finds it. You then put that argument in your project properties. The service code does basically the same thing as the Console code.
 
That is because you are trying to debug by pressing F10 to start the process.

To debug a service, you need to let Windows run the service, and then in Visual Studio you use "Debug>Attach to process" and attach to the running service.

If this sounds really inconvenient, it is. This is why a lot of people who write Windows services rely extensively on unit tests. And then when unit tests are not enough, they will either:
  • Write their service as a console an app primarily, and just give it the service entry points that Windows needs; OR
  • Write almost all of their service code in a DLL, and have a console app stub and a service stub that loads that DLL. The console app stub is for debugging, while the service stub has the entry points that Windows needs.


This service App is exe...console..exe..
This servise App is not DLL.
exe also becomes Debug>Process debug..
 
Yes, the program that Windows launches must be an .EXE but there is nothing that says that all the code needs to be in the .EXE. You can have the majority of the code live in a .DLL loaded by that .EXE.

Or alternatively, think of it this way: if you think that all the code of a service must live in the .EXE, then what happens when your code need to call the Windows API for reading or writing files that live in the KERNEL32.DLL or USER32.DLL. Are you saying that a service cannot read or write files because the code doesn't live in the .EXE?
 

Latest posts

Back
Top Bottom