Historically, debugging windows services can be a minor pain. One either has to either emulate the service controller behavior using a separate console application project or install the service, start it, set a break point and attach the debugger.
Mimicking a console application
Listing 1: ServiceBase extension method
/// <summary> /// Runs the service. /// </summary> /// <param name="serviceBase">The service base.</param> /// <param name="args">The args.</param> public static void RunService(this ServiceBase serviceBase, string[] args) { if (Debugger.IsAttached) { using (var autoResetEvent = new AutoResetEvent(false)) { const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.IgnoreCase | BindingFlags.Instance; var methodInfo = serviceBase.GetType().GetMethod("OnStart", flags); if (methodInfo != null) methodInfo.Invoke(serviceBase, new object[] { args }); autoResetEvent.WaitOne(); } } else { ServiceBase.Run(new[] { serviceBase }); } }
Pretty simple stuff…check that the debugger is attached…use reflection to invoke the protected ‘OnStart’ method and block the main thread infinitely with an ‘AutoResetEvent'; otherwise, run the service as normal. Here’s the usage:
internal static class Program { /// <summary> /// The main entry point for the application. /// </summary> private static void Main() { // ServiceBase[] ServicesToRun; // ServicesToRun = new ServiceBase[] // { // new Service1() // }; // ServiceBase.Run(ServicesToRun); new Service1().RunService(null); } }
Listing 3: Key service controller event handlers
private void OnServiceTimerElapsed(object sender, ElapsedEventArgs e) { _serviceTimer.Stop(); var dateTime = DateTime.Now; Debug.WriteLine(string.Format("Timer elapsed at {0} {1}...", dateTime.ToShortDateString(), dateTime.ToLongTimeString())); _serviceTimer.Start(); } protected override void OnStart(string[] args) { _serviceTimer.AutoReset = true; _serviceTimer.Enabled = true; _serviceTimer.Start(); Debug.WriteLine("Service started..."); }
To see this in action hit F5 or run the service project instance and you can see that the service is running based on the timer elapsed event in Listing 3.