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. 