.NET

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.

Related Articles

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button