简体   繁体   中英

Debugging a Windows Service

I am making a Windows Service and I want to debug it.

This is the error I get when I try to debug it:

Cannot start service from the command line or a debugger. A Windows service must be first installed and then started with the Server Explorer, Windows Services Administrative TOll or the NET start command.

I have already installed my service using InstallUtil , but I am still facing problems.

Also, when I try to attach a process, my service goes into the running mode, it never starts debugging.

EDIT: DO we have to reinstall the Windows Service everytime we make a change or just building it would suffice?

In your OnStart use something like this:

#if DEBUG
if(!System.Diagnostics.Debugger.IsAttached)
   System.Diagnostics.Debugger.Launch();
#endif

For the most use cases it's good enough to run the service as console application. To do this, I usually have the following startup code:

private static void Main(string[] args) {
    if (Environment.UserInteractive) {
        Console.WriteLine("My Service");
        Console.WriteLine();
        switch (args.FirstOrDefault()) {
        case "/install":
            ManagedInstallerClass.InstallHelper(new[] {Assembly.GetExecutingAssembly().Location});
            break;
        case "/uninstall":
            ManagedInstallerClass.InstallHelper(new[] {"/u", Assembly.GetExecutingAssembly().Location});
            break;
        case "/interactive":
            using (MyService service = new MyService(new ConsoleLogger())) {
                service.Start(args.Skip(1));
                Console.ReadLine();
                service.Stop();
            }
            break;
        default:
            Console.WriteLine("Supported arguments:");
            Console.WriteLine(" /install      Install the service");
            Console.WriteLine(" /uninstall    Uninstall the service");
            Console.WriteLine(" /interactive  Run the service interactively (on the console)");
            break;
        }
    } else {
        ServiceBase.Run(new MyService());
    }
}

This makes it easy not only to run and debug the service, but it can then also install and uninstall without needing the InstallUtil program.

This question has an excellent answer in making the service a console/service hybrid. See the answer from user marc_s . I don't want to duplicate the answer here.

I, personally for me, found the easiest solution is not change the code, by adding more mess and #if #else directives, but simply:

  1. Compile your service binaries in DEBUG mode
  2. Point installed service to DEBUG binaries
  3. Run service
  4. Use connect to process dialog of VS to connect to your running process连接到进程对话框

  5. Enjoy.

The good thing on this that you don't change the code so it's exactly the same as your production binaries, which, I think, is kind of important.

Good luck.

For debugging or testing your service without installing it, make changes in Program.cs like this.

static class Program
{
    static void Main()
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
    { 
      new MyService() 
    };
        ServiceBase.Run(ServicesToRun);
    }
   }

Change it to:

static class Program
{
static void Main()
{
    #if(!DEBUG)
       ServiceBase[] ServicesToRun;
       ServicesToRun = new ServiceBase[] 
   { 
        new MyService() 
   };
       ServiceBase.Run(ServicesToRun);
     #else
       MyService myServ = new MyService();
       myServ.Process();
       // here Process is my Service function
       // that will run when my service onstart is call
       // you need to call your own method or function name here instead of Process();
     #endif
    }
}

Try following this guide

EDIT: Personally, I have a console application in the same project that does all the work. I then just have the service run the Main of the console application. It makes debugging easy especially when just developing.

One way that I've done it before was to insert a Debugger.Break() in the service on start method. Compile and install the service. When it starts it break and open the debug with dialog, from there you should be able to attach and debug.

The Debugger.Launch method is a good way but I prefer to create a class that does the processing and call it from the service, This can then also be called from a win forms app. eg:

class ProcessingManager
{

    public void Start()
    {
     //do processing
    }

    public void Stop()
    {
    //stop
    }
}

then in your service / win forms app just create an instance of the processing class as a member variable and call the method on start and stop. It can be used in the service, or a win forms app with a start and stop button, which I find a lot quicker than attaching the debugger each time because you can set the windows application to start as default and add any breakpoints into the processing manager.

extract from service code:

namespace Service
{
    public partial class Service : ServiceBase
    {
        #region Members

        private ProcessingManager m_ProcessingManager = null;

        #endregion Members

        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public Service()
        {
            InitializeComponent();

            try
            {
                //Instantiate the processing manager
                m_ProcessingManager = new ProcessingManager();
            }
            catch (Exception ex)
            {
                ErrorHandler.LogError(ex);
            }
        }

        #endregion Constructor

        #region Events

        /// <summary>
        /// Starts the processing
        /// </summary>
        /// <param name="args">Parameters</param>
        protected override void OnStart(string[] args)
        {
            try
            {
                //Start the Processing
                m_ProcessingManager.Start();
            }
            catch (Exception ex)
            {
                ErrorHandler.LogError(ex);
            }
        }

        /// <summary>
        /// Service Stopped
        /// </summary>
        protected override void OnStop()
        {
            try
            {
                //Stop Processing
                m_ProcessingManager.Stop();
            }
            catch (Exception ex)
            {
                ErrorHandler.LogError(ex);
            }
        }

        #endregion Events
    }
}

What i always do is put a:

#if DEBUG 

 Thread.Sleep(20000) 

#endif

in the OnStart . That gives me 20s to attach.

Quick and easy, just remember to wrap it in an #if DEBUG #endif :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM