Debugging windows services
I’ve written a post before about how I debug windows service (i.e. run them from within Visual Studio without having to use “Attach to process”). I’ve come up with a new easier approach.
First of all, I’ve moved all logic from the service class. Instead I use a second class to control what should be started or not. So my Service class looks like this:
public partial class Service1 : ServiceBase { private ApplicationRunner _runner = new ApplicationRunner(); public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { _runner.Start(); } protected override void OnStop() { _runner.Stop(); } }
Hence I’m not dependent of the service class to be able to debug my application.
Now I just modify my Program.cs a bit:
internal static class Program { [DllImport("kernel32")] private static extern bool AllocConsole(); private static void Main() { if (Environment.CommandLine.Contains("-console") || Debugger.IsAttached) { if (Debugger.IsAttached) AllocConsole(); var runner = new ApplicationRunner(); runner.Start(); Console.WriteLine("Press ENTER to quit."); Console.ReadLine(); runner.Stop(); } ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new Service1() }; ServiceBase.Run(ServicesToRun); } }
The great thing with that is that can now also run my services from a command prompt if they fail to start properly. I just do myservice.exe -console
The AllocConsole()
creates a new console (making it an Console application instead of a windows service).
If you are interested, here is my ApplicationRunner
which starts all of my services etc. It’s using my Griffin.Framework and autofac:
internal class ApplicationRunner { private readonly ILog _logger = LogManager.GetLogger(typeof (ApplicationRunner)); private AutofacServiceLocator _adapter; private ApplicationServiceManager _applicationServiceManager; private BackgroundJobManager _backgroundJobManager; public void BuildContainer() { var cb = new ContainerBuilder(); cb.RegisterServices(Assembly.GetExecutingAssembly()); var container = cb.Build(); _adapter = new AutofacServiceLocator(container); } public void Start() { BuildContainer(); _logger.Info("Starting application services."); _applicationServiceManager = new ApplicationServiceManager(_adapter); _applicationServiceManager.ServiceRestartFailed += OnAppServiceFailed; _applicationServiceManager.Start(); _logger.Debug("Starting background jobs."); _backgroundJobManager = new BackgroundJobManager(_adapter); _backgroundJobManager.JobFailed += OnJobFailed; _backgroundJobManager.Start(); } public void Stop() { _logger.Info("Stopping application services."); _applicationServiceManager.Stop(); _logger.Info("Stopping background jobs."); _backgroundJobManager.Stop(); } private void OnAppServiceFailed(object sender, ApplicationServiceFailedEventArgs e) { _logger.Error("Service failed.", e.Exception); } private void OnJobFailed(object sender, BackgroundJobFailedEventArgs e) { _logger.Error("Job failed.", e.Exception); } }
A sample service can look like this:
[ContainerService(ContainerLifetime.SingleInstance)] class QueueReader : ApplicationServiceThread { private readonly IScopedActionInvoker _invoker; private ServiceBrokerService _ssb; public QueueReader(IScopedActionInvoker invoker) { _invoker = invoker; var queueName = ConfigurationManager.AppSettings["QueueName"]; IQueueConfiguration config = new AppConfigQueueConfiguration(queueName) { MessageSerializer = new XmlMessageSerializer(new[] {typeof (MultiMessage), typeof (TrainInfo)}) }; _ssb = new ServiceBrokerService(config); } protected override void Run(WaitHandle shutdownHandle) { while (!shutdownHandle.WaitOne(0)) { var msgs =_ssb.Receive(new RecieveSettings {MaxAmountOfMessages = 100, MaxWaitTime = TimeSpan.FromSeconds(1)}); var messages = new List<MultiMessage>(); foreach (var msg in msgs) { if (msg.MessageTypeName == ReceivedMessage.EndConversationType) { _ssb.EndConversation(msg.Conversation); } else { messages.Add((MultiMessage)msg.Body); } } _invoker.Execute<IMessageHandler>(x=>x.Process(messages)); } } }
Reference: | Debugging windows services from our NCG partner Jonas Gauffin at the jgauffin’s coding den blog. |