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. |