338

Is there an easier way to step through the code than to start the service through the Windows Service Control Manager and then attaching the debugger to the thread? It's kind of cumbersome and I'm wondering if there is a more straightforward approach.

Uwe Keim
  • 36,867
  • 50
  • 163
  • 268
Mats
  • 13,840
  • 29
  • 73
  • 106
  • I created this User Voice ticket. Consider voting for it: https://visualstudio.uservoice.com/forums/121579-visual-studio-ide/suggestions/35367148-make-it-easier-to-debug-windows-services – David Sep 10 '18 at 18:58

28 Answers28

274

If I want to quickly debug the service, I just drop in a Debugger.Break() in there. When that line is reached, it will drop me back to VS. Don't forget to remove that line when you are done.

UPDATE: As an alternative to #if DEBUG pragmas, you can also use Conditional("DEBUG_SERVICE") attribute.

[Conditional("DEBUG_SERVICE")]
private static void DebugMode()
{
    Debugger.Break();
}

On your OnStart, just call this method:

public override void OnStart()
{
     DebugMode();
     /* ... do the rest */
}

There, the code will only be enabled during Debug builds. While you're at it, it might be useful to create a separate Build Configuration for service debugging.

riQQ
  • 4,188
  • 4
  • 19
  • 33
jop
  • 77,529
  • 10
  • 52
  • 52
  • 46
    Or you could use Debugger.Launch() you will have to include a using statement for The Systems.Diagnostics namespace. – Omar Kooheji Sep 24 '08 at 08:39
  • 1
    Your blog post worked just fine and saved my day:) however the Debugger.Break() didn't worked for me. it seems that .Net skips the DebugMode function for some optimization-related reasons. – Bizhan Dec 20 '11 at 01:09
  • 3
    Debugger.Launch() works for me when Debugger.Break() doesn't. (Process exits with code 255.) – Oliver Bock Dec 18 '14 at 02:50
  • How are you guys getting this to work? Nothing happens. I've tried Break() and Launch(). – 4thSpace Mar 22 '16 at 17:05
  • 14
    @4thSpace: 1. create an installer for your service, so you can install your service. 2. Add the line Debugger.Launch(); at the beginning of your Main(). 3. Build your code in Debug-mode. 4. Overwrite the installed dll's with the debug-dll's. 5. Start the service from the Windows Services panel. Now a popup appears to ask you to attach to a debugger. This way worked for me. Hopefully for you as well. – ffonz Apr 13 '16 at 08:41
215

I also think having a separate "version" for normal execution and as a service is the way to go, but is it really required to dedicate a separate command line switch for that purpose?

Couldn't you just do:

public static int Main(string[] args)
{
  if (!Environment.UserInteractive)
  {
    // Startup as service.
  }
  else
  {
    // Startup as application
  }
}

That would have the "benefit", that you can just start your app via doubleclick (OK, if you really need that) and that you can just hit F5 in Visual Studio (without the need to modify the project settings to include that /console Option).

Technically, the Environment.UserInteractive checks if the WSF_VISIBLE Flag is set for the current window station, but is there any other reason where it would return false, apart from being run as a (non-interactive) service?

Christian.K
  • 42,600
  • 9
  • 89
  • 127
  • Great! I earlier used an "if #debug" method to start as application if debugging, otherwise a service. This leads to the app not being runnable as a service if you want to debug it, but your solution solves this and let it be runnable in all four combinations of service/app and release/debug. – Jonas Mar 05 '10 at 13:39
  • 31
    If you don't want the program to run when it's double-clicked (users might get confused and run several instances etc), then you can use `System.Diagnostics.Debugger.IsAttached` instead of `Environment.UserInteractive`. – Blorgbeard May 17 '10 at 15:22
  • 5
    _but is there any other reason where it would return false, apart from being run as a (non-interactive) service?_ I can think of one: A scheduled task which does not attach to a console. – Hogan Sep 26 '11 at 20:13
  • 7
    i use command line parameters for this case. --install to install the service, --uninstall to uninstall the service and --interactive to run the service as application. i add --interactive to project options (Debugging > Command Arguments). So i can easily debug from VS. double clicking will not create an unwanted running instance since --interactive is required. just my 2 cents. – Emir Akaydın Feb 14 '12 at 16:42
  • @EmirAkaydın Yes, actually I have command line parameters as "backup" as well. However, I actually *wanted* to have an "interactive" instance when double clicking and not and error message about the fact that a service cannot be started that way. Varying goals I guess ;-) – Christian.K Feb 16 '12 at 09:36
  • +1 from me, but for readability's sake, invert the logic i.e. if Interactive then RunInteractively else RunService :-) – David Keaveny Apr 03 '13 at 23:14
  • I also use this approach, it's really fantastic for running tests, etc, but there can be problems with running the app in different contexts, for example, if you wanted to perform a screen capture. – Michael Silver Jun 25 '17 at 00:08
129

When I set up a new service project a few weeks ago I found this post. While there are many great suggestions, I still didn't find the solution I wanted: The possibility to call the service classes' OnStart and OnStop methods without any modification to the service classes.

The solution I came up with uses the Environment.Interactive the select running mode, as suggested by other answers to this post.

static void Main()
{
    ServiceBase[] servicesToRun;
    servicesToRun = new ServiceBase[] 
    {
        new MyService()
    };
    if (Environment.UserInteractive)
    {
        RunInteractive(servicesToRun);
    }
    else
    {
        ServiceBase.Run(servicesToRun);
    }
}

The RunInteractive helper uses reflection to call the protected OnStart and OnStop methods:

static void RunInteractive(ServiceBase[] servicesToRun)
{
    Console.WriteLine("Services running in interactive mode.");
    Console.WriteLine();

    MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart", 
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Starting {0}...", service.ServiceName);
        onStartMethod.Invoke(service, new object[] { new string[] { } });
        Console.Write("Started");
    }

    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine(
        "Press any key to stop the services and end the process...");
    Console.ReadKey();
    Console.WriteLine();

    MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop", 
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Stopping {0}...", service.ServiceName);
        onStopMethod.Invoke(service, null);
        Console.WriteLine("Stopped");
    }

    Console.WriteLine("All services stopped.");
    // Keep the console alive for a second to allow the user to see the message.
    Thread.Sleep(1000);
}

This is all the code required, but I also wrote walkthrough with explanations.

Anders Abel
  • 64,109
  • 15
  • 143
  • 213
  • This makes a good extension method for ServiceBase[]. I have multiple services in my solution so rather than having a common base class for Program.cs, I just call servicesToRun.RunInteractive(args). Nice solution @Anders! – David Keaveny Apr 03 '13 at 23:13
  • 3
    Great solution indeed. I created a simple extension for ServiceBase[] as David suggested which allows to run services in just one line of code: http://pastebin.com/F0fhhG2R – Funbit Apr 26 '13 at 03:41
  • @Funbit That's really neat - would you mind if I published it on my blog as an update to the walkthrough? – Anders Abel Apr 26 '13 at 08:14
  • Having an issue, running in interactive mode seems to keep me from sending Service commands through the ServiceController. If I have a service running named "MyService" and then try to send a service command like: (new ServiceController("MyService")).ExecuteCommand(160); It fails because the ServiceController returns a null in interactive mode, and only works when running as a service. making it difficult to debug executing service commands. – stephenbayer Jun 20 '14 at 21:44
  • 4
    +1 A former colleague of mine created an "EasyRunService" base class (which inherits ServiceProcess) which does pretty much the same thing, but without the need for reflection (because OnStart is now in the base class). It really makes debugging a windows service a breeze. – sondergard Jan 29 '15 at 13:40
  • I don't get a console using @Funbit 's solution. – Chazt3n May 04 '16 at 14:57
  • Changing the output to Console App changes the installation of my app or? – Chazt3n May 04 '16 at 15:27
  • 3
    @Chazt3n Make sure that your project output type is set to "Console Application". As for the service installation, It does not matter which output type is selected, the behavior is the same. – Funbit May 07 '16 at 01:52
  • I was unable to install as a Windows service with CApp selected, I changed the code wait forever instead – Chazt3n May 09 '16 at 19:19
  • 2
    Still a great solution! The only thing I would add (as shown in the `walk through`) is to make sure you go into the project's properties and change the output type to `Console Application` before you try to compile and run. Find it at `Project Properties -> Application -> Output type -> Console Application`. Also, for this to work properly for me I ended up having to run the application using the `start` command. Ex: `C:\"my app name.exe" -service` would not work for me. Instead I used `C:\start /wait "" "my app name.exe" -service` – Arvo Bowen Jul 11 '16 at 17:43
  • +1 This is a great solution (Windows Service - .NET 4.0). Shout out to @Funbit for his extension methods for ServiceBase as per his comment above! – Connor Goddard Dec 19 '16 at 12:06
  • man .. you are the boss .. also strongly agree with @ArvoBowen that we need to change the output type to Console app otherwise Console.ReadKey() will thrown exception and service will be stopeed. – Naveed Khan Jun 03 '20 at 12:33
49

Sometimes it is important to analyze what's going on during the start up of the service. Attaching to the process does not help here, because you are not quick enough to attach the debugger while the service is starting up.

The short answer is, I am using the following 4 lines of code to do this:

#if DEBUG
    base.RequestAdditionalTime(600000); // 600*1000ms = 10 minutes timeout
    Debugger.Launch(); // launch and attach debugger
#endif

These are inserted into the OnStart method of the service as follows:

protected override void OnStart(string[] args)
{
    #if DEBUG
       base.RequestAdditionalTime(600000); // 10 minutes timeout for startup
       Debugger.Launch(); // launch and attach debugger
    #endif
    MyInitOnstart(); // my individual initialization code for the service
    // allow the base class to perform any work it needs to do
    base.OnStart(args);
}

For those who haven't done it before, I have included detailed hints below, because you can easily get stuck. The following hints refer to Windows 7x64 and Visual Studio 2010 Team Edition, but should be valid for other environments, too.


Important: Deploy the service in "manual" mode (using either the InstallUtil utility from the VS command prompt or run a service installer project you have prepared). Open Visual Studio before you start the service and load the solution containing the service's source code - set up additional breakpoints as you require them in Visual Studio - then start the service via the Service Control Panel.

Because of the Debugger.Launch code, this will cause a dialog "An unhandled Microsoft .NET Framework exception occured in Servicename.exe." to appear. Click Elevate Yes, debug Servicename.exe as shown in the screenshot:
FrameworkException

Afterwards, escpecially in Windows 7 UAC might prompt you to enter admin credentials. Enter them and proceed with Yes:

UACPrompt

After that, the well known Visual Studio Just-In-Time Debugger window appears. It asks you if you want to debug using the delected debugger. Before you click Yes, select that you don't want to open a new instance (2nd option) - a new instance would not be helpful here, because the source code wouldn't be displayed. So you select the Visual Studio instance you've opened earlier instead: VSDebuggerPrompt

After you have clicked Yes, after a while Visual Studio will show the yellow arrow right in the line where the Debugger.Launch statement is and you are able to debug your code (method MyInitOnStart, which contains your initialization). VSDebuggerBreakpoint

Pressing F5 continues execution immediately, until the next breakpoint you have prepared is reached.

Hint: To keep the service running, select Debug -> Detach all. This allows you to run a client communicating with the service after it started up correctly and you're finished debugging the startup code. If you press Shift+F5 (stop debugging), this will terminate the service. Instead of doing this, you should use the Service Control Panel to stop it.

Note that

  • If you build a Release, then the debug code is automatically removed and the service runs normally.

  • I am using Debugger.Launch(), which starts and attaches a debugger. I have tested Debugger.Break() as well, which did not work, because there is no debugger attached on start up of the service yet (causing the "Error 1067: The process terminated unexpectedly.").

  • RequestAdditionalTime sets a longer timeout for the startup of the service (it is not delaying the code itself, but will immediately continue with the Debugger.Launch statement). Otherwise the default timeout for starting the service is too short and starting the service fails if you don't call base.Onstart(args) quickly enough from the debugger. Practically, a timeout of 10 minutes avoids that you see the message "the service did not respond..." immediately after the debugger is started.

  • Once you get used to it, this method is very easy because it just requires you to add 4 lines to an existing service code, allowing you quickly to gain control and debug.

Matt
  • 21,449
  • 14
  • 100
  • 149
  • 1
    Out of curiousity, do you know if there is a timeout for user interaction with the Debugger.Launch() user prompt? – Shiv Nov 25 '14 at 04:54
  • 1
    As described, `base.RequestAdditionalTime(600000)` will prevent the service control from terminating the service for 10 minutes if it does not call `base.OnStart(args)` within that timespan). Apart from that, I remember that UAC will also abort if you don't enter the admin credentials after a while (I don't know how many seconds exactly, but I think you have to enter it within a minute, else UAC aborts), which will terminate the debug session. – Matt Nov 25 '14 at 09:02
  • 2
    I found this to be the best method for debugging CustomCommand messages. +1. – Justin Jul 19 '16 at 13:36
40

What I usually do is encapsulate the logic of the service in a separate class and start that from a 'runner' class. This runner class can be the actual service or just a console application. So your solution has (atleast) 3 projects:

/ConsoleRunner
   /....
/ServiceRunner
   /....
/ApplicationLogic
   /....
Paul van Brenk
  • 7,081
  • 2
  • 30
  • 37
  • 1
    I used to use this approach too, but I think a combination of this and the answer above works a treat. – RobS Feb 24 '09 at 04:55
29

This YouTube video by Fabio Scopel explains how to debug a Windows service quite nicely... the actual method of doing it starts at 4:45 in the video...

Here is the code explained in the video... in your Program.cs file, add the stuff for the Debug section...

namespace YourNamespace
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
#if DEBUG
            Service1 myService = new Service1();
            myService.OnDebug();
            System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new Service1()
            };
            ServiceBase.Run(ServicesToRun);
#endif

        }
    }
}

In your Service1.cs file, add the OnDebug() method...

    public Service1()
    {
        InitializeComponent();
    }

    public void OnDebug()
    {
        OnStart(null);
    }

    protected override void OnStart(string[] args)
    {
        // your code to do something
    }

    protected override void OnStop()
    {
    }

How it works

Basically you have to create a public void OnDebug() that calls the OnStart(string[] args) as it's protected and not accessible outside. The void Main() program is added with #if preprocessor with #DEBUG.

Visual Studio defines DEBUG if project is compiled in Debug mode.This will allow the debug section(below) to execute when the condition is true

Service1 myService = new Service1();
myService.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);

And it will run just like a console application, once things go OK you can change the mode Release and the regular else section will trigger the logic

Vinod Srivastav
  • 2,633
  • 1
  • 21
  • 31
Jason Miller
  • 183
  • 3
  • 8
15

UPDATE

This approach is by far the easiest:

http://www.codeproject.com/KB/dotnet/DebugWinServices.aspx

I leave my original answer below for posterity.


My services tend to have a class that encapsulates a Timer as I want the service to check at regular intervals whether there is any work for it to do.

We new up the class and call StartEventLoop() during the service start-up. (This class could easily be used from a console app too.)

The nice side-effect of this design is that the arguments with which you set up the Timer can be used to have a delay before the service actually starts working, so that you have time to attach a debugger manually.

p.s. How to attach the debugger manually to a running process...?

using System;
using System.Threading;
using System.Configuration;    

public class ServiceEventHandler
{
    Timer _timer;
    public ServiceEventHandler()
    {
        // get configuration etc.
        _timer = new Timer(
            new TimerCallback(EventTimerCallback)
            , null
            , Timeout.Infinite
            , Timeout.Infinite);
    }

    private void EventTimerCallback(object state)
    {
        // do something
    }

    public void StartEventLoop()
    {
        // wait a minute, then run every 30 minutes
        _timer.Change(TimeSpan.Parse("00:01:00"), TimeSpan.Parse("00:30:00");
    }
}

Also I used to do the following (already mentioned in previous answers but with the conditional compiler [#if] flags to help avoid it firing in a Release build).

I stopped doing it this way because sometimes we'd forget to build in Release and have a debugger break in an app running on a client demo (embarrasing!).

#if DEBUG
if (!System.Diagnostics.Debugger.IsAttached)
{
    System.Diagnostics.Debugger.Break();
}
#endif
rohancragg
  • 4,904
  • 5
  • 32
  • 44
13

static void Main()
{
#if DEBUG
                // Run as interactive exe in debug mode to allow easy
                // debugging.

                var service = new MyService();
                service.OnStart(null);

                // Sleep the main thread indefinitely while the service code
                // runs in .OnStart

                Thread.Sleep(Timeout.Infinite);
#else
                // Run normally as service in release mode.

                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[]{ new MyService() };
                ServiceBase.Run(ServicesToRun);
#endif
}
Thomas Bratt
  • 40,822
  • 34
  • 113
  • 133
  • [Sorry about no explanation with the code - markdown problems] Should run normally from MS Visual Studio (F5) in debug builds. Still runs as a normal service in release builds. – Thomas Bratt Sep 29 '08 at 21:48
  • Combine this with the solution above by Christian K. to use the "Environment.UserInteractive" property and the solution is really clean and simple. – Ben Robbins Mar 25 '10 at 10:03
  • `OnStart` is `protected` and you can't modify the access level :( – Eduard Luca Aug 24 '13 at 20:20
10

You can also start the service through the command prompt (sc.exe).

Personally, I'd run the code as a stand-alone program in the debugging phase, and when most bugs are ironed out, change to running as service.

akauppi
  • 14,244
  • 12
  • 73
  • 94
10

What I used to do was to have a command line switch which would start the program either as a service or as a regular application. Then, in my IDE I would set the switch so that I could step through my code.

With some languages you can actually detect if it's running in an IDE, and perform this switch automatically.

What language are you using?

RB.
  • 33,692
  • 12
  • 79
  • 121
9

Use the TopShelf library.

Create a console application then configure setup in your Main

class Program
    {
        static void Main(string[] args)
        {
            HostFactory.Run(x =>
            {

                // setup service start and stop.
                x.Service<Controller>(s =>
                {
                    s.ConstructUsing(name => new Controller());
                    s.WhenStarted(controller => controller.Start());
                    s.WhenStopped(controller => controller.Stop());
                });

                // setup recovery here
                x.EnableServiceRecovery(rc =>
                {
                    rc.RestartService(delayInMinutes: 0);
                    rc.SetResetPeriod(days: 0);
                });

                x.RunAsLocalSystem();
            });
        }
}

public class Controller
    {
        public void Start()
        {

        }

        public void Stop()
        {

        }
    }

To debug your service, just hit F5 in visual studio.

To install service, type in cmd "console.exe install"

You can then start and stop service in the windows service manager.

Misterhex
  • 819
  • 11
  • 17
  • Their licensing was too confusing to understand – Alex Gordon May 15 '16 at 20:56
  • They use Apache License afaik. Topshelf is the easiest way I have used to develop and debug windows services. Super easy to use. Develop as a console application. Install as a service with one command line switch. Highly recommended. – robs Jan 23 '18 at 02:46
  • TopShelf saved me tons of time. Thx – L_7337 May 07 '19 at 18:43
8

I think it depends on what OS you are using, Vista is much harder to attach to Services, because of the separation between sessions.

The two options I've used in the past are:

  • Use GFlags (in the Debugging Tools for Windows) to setup a permanent debugger for a process. This exists in the "Image File Execution Options" registry key and is incredibly useful. I think you'll need to tweak the Service settings to enable "Interact with Desktop". I use this for all types of debugging, not just services.
  • The other option, is to separate the code a bit, so that the service part is interchangable with a normal app startup. That way, you can use a simple command line flag, and launch as a process (rather than a Service), which makes it much easier to debug.

Hope this helps.

RichS
  • 2,853
  • 27
  • 24
6

I like to be able to debug every aspect of my service, including any initialization in OnStart(), while still executing it with full service behavior within the framework of the SCM... no "console" or "app" mode.

I do this by creating a second service, in the same project, to use for debugging. The debug service, when started as usual (i.e. in the services MMC plugin), creates the service host process. This gives you a process to attach the debugger to even though you haven't started your real service yet. After attaching the debugger to the process, start your real service and you can break into it anywhere in the service lifecycle, including OnStart().

Because it requires very minimal code intrusion, the debug service can easily be included in your service setup project, and is easily removed from your production release by commenting out a single line of code and deleting a single project installer.

Details:

1) Assuming you are implementing MyService, also create MyServiceDebug. Add both to the ServiceBase array in Program.cs like so:

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
        { 
            new MyService(),
            new MyServiceDebug()
        };
        ServiceBase.Run(ServicesToRun);
    }

2) Add the real service AND the debug service to the project installer for the service project:

enter image description here

Both services (real and debug) get included when you add the service project output to the setup project for the service. After installation, both services will appear in the service.msc MMC plugin.

3) Start the debug service in MMC.

4) In Visual Studio, attach the debugger to the process started by the debug service.

5) Start the real service and enjoy debugging.

BitMask777
  • 2,223
  • 23
  • 35
5

When I write a service I put all the service logic in a dll project and create two "hosts" that call into this dll, one is a Windows service and the other is a command line application.

I use the command line application for debugging and attach the debugger to the real service only for bugs I can't reproduce in the command line application.

I you use this approach just remember that you have to test all the code while running in a real service, while the command line tool is a nice debugging aid it's a different environment and it doesn't behave exactly like a real service.

Nir
  • 28,165
  • 10
  • 65
  • 101
4

When developing and debugging a Windows service I typically run it as a console application by adding a /console startup parameter and checking this. Makes life much easier.

static void Main(string[] args) {
    if (Console.In != StreamReader.Null) {
        if (args.Length > 0 && args[0] == "/console") {
            // Start your service work.
        }
    }
}
Maurice
  • 27,324
  • 5
  • 46
  • 61
  • Till you have to debug service specific issues. – leppie Sep 24 '08 at 08:19
  • True, then you have to attach the debugger to the actual service process. But in most cases bugs are going to appear either way and development is much easier. – Maurice Sep 24 '08 at 08:24
4

How about Debugger.Break() in the first line?

leppie
  • 109,129
  • 16
  • 185
  • 292
2

To debug Windows Services I combine GFlags and a .reg file created by regedit.

  1. Run GFlags, specifying the exe-name and vsjitdebugger
  2. Run regedit and go to the location where GFlags sets his options
  3. Choose "Export Key" from the file-menu
  4. Save that file somewhere with the .reg extension
  5. Anytime you want to debug the service: doubleclick on the .reg file
  6. If you want to stop debugging, doubleclick on the second .reg file

Or save the following snippets and replace servicename.exe with the desired executable name.


debugon.reg:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\servicename.exe]
"GlobalFlag"="0x00000000"
"Debugger"="vsjitdebugger.exe"

debugoff.reg:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\servicename.exe]
"GlobalFlag"="0x00000000"
  • Does this still work on Win 7 / Win 2008? It's the approach from http://support.microsoft.com/kb/824344 but it relies on interactive services, and I thought they got killed off? It always used to be my preferred option (since startup issues might come up in production, where inserting a Debugger.Break() into the code might not be an option). – piers7 Apr 09 '10 at 13:20
2

Here is the simple method which I used to test the service, without any additional "Debug" methods and with integrated VS Unit Tests.

[TestMethod]
public void TestMyService()
{
    MyService fs = new MyService();

    var OnStart = fs.GetType().BaseType.GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

    OnStart.Invoke(fs, new object[] { null });
}

// As an extension method
public static void Start(this ServiceBase service, List<string> parameters)
{
     string[] par = parameters == null ? null : parameters.ToArray();

     var OnStart = service.GetType().GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

     OnStart.Invoke(service, new object[] { par });
}
MisterDr
  • 36
  • 3
1

For routine small-stuff programming I've done a very simple trick to easily debug my service:

On start of the service, I check for a command line parameter "/debug". If the service is called with this parameter, I don't do the usual service startup, but instead start all the listeners and just display a messagebox "Debug in progress, press ok to end".

So if my service is started the usual way, it will start as service, if it is started with the command line parameter /debug it will act like a normal program.

In VS I'll just add /debug as debugging parameter and start the service program directly.

This way I can easily debug for most small kind problems. Of course, some stuff still will need to be debugged as service, but for 99% this is good enough.

Sam
  • 26,538
  • 45
  • 157
  • 240
1

For trouble-shooting on existing Windows Service program, use 'Debugger.Break()' as other guys suggested.

For new Windows Service program, I would suggest using James Michael Hare's method http://geekswithblogs.net/BlackRabbitCoder/archive/2011/03/01/c-toolbox-debug-able-self-installable-windows-service-template-redux.aspx

Yang You
  • 2,278
  • 21
  • 28
1
#if DEBUG
    System.Diagnostics.Debugger.Break();
#endif
Ervin Ter
  • 1,045
  • 3
  • 11
  • 17
1

Just put your debugger lunch anywhere and attach Visualstudio on startup

#if DEBUG
    Debugger.Launch();
#endif

Also you need to start VS as Administatrator and you need to allow, that a process can automatically be debugged by a diffrent user (as explained here):

reg add "HKCR\AppID{E62A7A31-6025-408E-87F6-81AEB0DC9347}" /v AppIDFlags /t REG_DWORD /d 8 /f
wotanii
  • 1,507
  • 11
  • 27
1

Use Windows Service Template C# project to create a new service app https://github.com/HarpyWar/windows-service-template

There are console/service mode automatically detected, auto installer/deinstaller of your service and several most used features are included.

HarpyWar
  • 113
  • 1
  • 5
1
static class Program
{
    static void Main()
    {
        #if DEBUG

        // TODO: Add code to start application here

        //    //If the mode is in debugging
        //    //create a new service instance
        Service1 myService = new Service1();

        //    //call the start method - this will start the Timer.
        myService.Start();

        //    //Set the Thread to sleep
        Thread.Sleep(300000);

        //    //Call the Stop method-this will stop the Timer.
        myService.Stop();

         #else
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
        { 
            new Service1() 
        };

        ServiceBase.Run(ServicesToRun);
         #endif
    }
}
Andre Hofmeister
  • 2,814
  • 10
  • 43
  • 68
Mansoor
  • 77
  • 5
  • this is easier. just change the solution config setting to debug, run the project/solution, add breakpoints as you go. – Bahamut Aug 30 '18 at 03:59
1

I use a variation on JOP's answer. Using command line parameters you can set the debugging mode in the IDE with project properties or through the Windows service manager.

protected override void OnStart(string[] args)
{
  if (args.Contains<string>("DEBUG_SERVICE"))
  {
    Debugger.Break();
  }
  ...
}
0

You have two options to do the debugging.

  1. create a log file : Personally i prefer a separate log file like text file rather using the application log or event log.But this will cost you a lot on behalf of time, because its still hard to figure our where the exact error location is
  2. Convert the application to console application : this will enable you, all the debugging tools which we can use in VS.

Please refer THIS blog post that i created for the topic.

Sandaru
  • 1,179
  • 1
  • 18
  • 35
0

Just paste

Debugger.Break();

any where in you code.

For Example ,

internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        private static void Main()
        {
            Debugger.Break();
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new Service1()
            };
            ServiceBase.Run(ServicesToRun);
        }
    }

It will hit Debugger.Break(); when you run your program.

Chutipong Roobklom
  • 2,573
  • 1
  • 14
  • 20
0

The best option is to use the 'System.Diagnostics' namespace.

Enclose your code in if else block for debug mode and release mode as shown below to switch between debug and release mode in visual studio,

#if DEBUG  // for debug mode
       **Debugger.Launch();**  //debugger will hit here
       foreach (var job in JobFactory.GetJobs())
            {
                //do something 
            }

#else    // for release mode
      **Debugger.Launch();**  //debugger will hit here
     // write code here to do something in Release mode.

#endif
Amey P Naik
  • 612
  • 7
  • 16