4

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?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Neha
  • 39
  • 1
  • 7

9 Answers9

4

In your OnStart use something like this:

#if DEBUG
if(!System.Diagnostics.Debugger.IsAttached)
   System.Diagnostics.Debugger.Launch();
#endif
Mrchief
  • 75,126
  • 20
  • 142
  • 189
  • Thanks a lot!! :) It pops up the Just in Time Debugger and then i can attach a debugger :) – Neha Jul 25 '11 at 17:18
  • I wish i could do that but i don't have enough reputation Also how do u accept an answer? – Neha Jul 25 '11 at 17:29
  • You'd see a tick mark below on left to an answer. Click that. – Mrchief Jul 25 '11 at 17:31
  • Also can u help me with this: DO we have to reinstall the Windows Service everytime we make a change or just building it would suffice? – Neha Jul 25 '11 at 17:49
  • Just building it would suffice in most cases but not always. To keep my answer simple: If you don't see your changes reflecting, reinstall. – Mrchief Jul 25 '11 at 18:15
4

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.

Lucero
  • 59,176
  • 9
  • 122
  • 152
4

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.

Community
  • 1
  • 1
Bryan Crosby
  • 6,486
  • 3
  • 36
  • 55
2

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 connect to process dialog

  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.

Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
Tigran
  • 61,654
  • 8
  • 86
  • 123
0

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
    }
}
Naila Akbar
  • 3,033
  • 4
  • 34
  • 76
0

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.

Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
Tom Squires
  • 8,848
  • 12
  • 46
  • 72
  • Do not simply answer with links to other sites. SO should be a one stop solution for people coming here, not a proxy to google. You can always add or enhance with some code snippet or info. – Mrchief Jul 22 '11 at 15:00
  • when I try to attach a process, my service goes into the running mode, it never starts debugging. – Neha Jul 22 '11 at 16:53
0

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.

BRaul
  • 226
  • 1
  • 2
  • The problem I am facing now is that the project is in Debug mode but it just goes through 4-5 lines and then stops! – Neha Jul 22 '11 at 16:58
0

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
    }
}
WraithNath
  • 17,658
  • 10
  • 55
  • 82
-1

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 :)

jaywayco
  • 5,846
  • 6
  • 25
  • 40
  • I did this: protected override void OnStart(string[] args) { if (DEBUG) Thread.Sleep(20000); } and It gives me this error: The name 'DEBUG' does not exist in the current context The name 'Thread' does not exist in the current context – Neha Jul 22 '11 at 15:37
  • DEBUG is a preprocessor statement so it should be "#if DEBUG (do something) #endif" make sure you have the #'s and no {}'s – jaywayco Jul 25 '11 at 09:25
  • sorry i am still not getting it.Could you write a sample code? – Neha Jul 25 '11 at 17:11
  • Also can u help me with this: DO we have to reinstall the Windows Service everytime we make a change or just building it would suffice? – Neha Jul 25 '11 at 17:42
  • ok. What i would normally do would be to "install" the service. To do this open the visual studio command line and type in "installutil servicename.exe" (servicename.exe would be the full path of the compiled exe) This then makes your service available in the OS Services.msc console. Then, in OnStart, i would add the line Thread.Sleep(20000); as the first executed line of code. Compile your service -> Go to Services.msc and click start on your service -> go to visual studio put a breakpoint on the first line of code after the "sleep" and attach to process. – jaywayco Jul 25 '11 at 20:31
  • You now can start, stop your service as a normal service and you have 20s to attach to it in VS. – jaywayco Jul 25 '11 at 20:32
  • The #if DEBUG before the sleep statement and the #endif after would mean the sleep statement would only be executed when the code is build in Debug mode – jaywayco Jul 25 '11 at 20:36