Creating easy to debug Windows Services in .NET

When you want a process to run continuously, even when no user is logged in to a machine and when you want that process to start running as soon as Windows does, you may want to create a Windows Service.

Using .NET’s System.ServiceProcess namespace you can easily write code that allows your program to act as a Windows Service. The namespace also includes classes that let you manage services, such as starting, stopping and installing them.

Creating a basic Windows Service

When using the Visual Studio template for a “Windows Service Application”, a project will be created that shows the basic skeleton. This is easily recreated:

  1. Create a new Console Application.
  2. Add a reference to System.ServiceProcess.
  3. Write the following code:
public static class Program
{
  public static void Main(string[] args)
  {
    ServiceBase.Run(new SimpleService());
  }
}

public class SimpleService : ServiceBase
{
  public SimpleService()
  {
    ServiceName = "SimpleService";
  }
    
  protected override void OnStart(string[] args)
  {
    // Start your service!
  }
}

However, if you now hit F5, you’ll get an error saying “Cannot start service from the command line or a debugger. A Windows Service must first be installed […].”:

Service Start Failure

Attaching the debugger

The MSDN way to debug a service is pretty convoluted: you’ll have to install the service, start it and attach Visual Studio’s debugger to the service process. And then when you spot an issue and fix it, you’ll have to perform the mentioned steps again.

Environment.UserInteractive

You can easily detect whether the current process is running “user-interactive” as defined on MSDN testing Environment.UserInteractive, adapted from Stack Overflow:

public static class Program
{
  public static void Main(string[] args)
  {
    // Instantiate the service.
    var myService = new MyService();

    // User Interactive? Debug!
    if (Environment.UserInteractive)
    {
      myService.Start();
    }
    else
    {
      // Otherwise, run as Windows Service.
      ServiceBase.Run(myService);
    }
}

public class MyService : ServiceBase
{
  public void Start()
  {
    // Do the actual starting.
  }

  /// <summary>
  /// Called when this service is started 
  /// through the Service Control Manager.
  /// </summary>
  /// <param name="args"></param>
  protected override void OnStart(string[] args)
  {
    this.Start();
  }        
}

Now when you hit F5 (which automatically attaches the debugger to your process), you’re debugging your service logic! This is the simplest and least invasive way making it possible to debug a Windows Service without installing it and attaching the debugger.

However, you preferably want extract the service logic and do your debugging on that class. This way you can reuse the base class among your projects and you improve testability.

In order to support more options than just debugging, we also support command line arguments:

public static class Program
{
  public static void Main(string[] args)
  {
    // Instantiate the business logic of the service.
    IServiceLogic myServiceLogic = new MyServiceLogic();

    // No arguments? Run the Service and exit when service exits.
    if (!args.Any())
    {
      // CustomServiceBase operates on an IServiceLogic instance,
      // which is injected here using myServiceLogic.
      var myService = new CustomServiceBase(myServiceLogic);
      ServiceBase.Run(myService);
      return;
    }

    // Parse arguments.
    switch (args.First().ToUpperInvariant())
    {
      case "/D":
      case "/DEBUG":
        myServiceLogic.Start(args.Skip(1));
        break;
      default:
        PrintUsage();
        break;
    }
  }
  
  private static void PrintUsage()
  {
    Console.WriteLine("Usage:");
    Console.WriteLine();
    Console.Write(" {0} ", Path.GetFileName(Assembly.GetEntryAssembly().Location));
    Console.WriteLine("/D[ebug]\tStart the service logic");
  }
}

An interface IServiceLogic has been introduced, which defines the methods that can be called on the logic. This interface is implemented by MyServiceLogic:

public interface IServiceLogic
{
  void Start(IEnumerable<string> args);

  void Stop();
}

public class MyServiceLogic : IServiceLogic
{
  public void Start(IEnumerable<string> args)
  {
    Debug.WriteLine("Start(): {0}", string.Join(", ", args));
  }

  public void Stop()
  {
    // Do nothing.
  }
}

The CustomServiceBase looks like this:

[System.ComponentModel.DesignerCategory("Code")] // Prevent double-clicking the file to open designer mode.
public class CustomServiceBase : ServiceBase
{
  private readonly IServiceLogic _serviceLogic;

  public CustomServiceBase(IServiceLogic serviceLogic)
  {
    ServiceName = serviceLogic.ServiceName;
    _serviceLogic = serviceLogic;
  }

  protected override void OnStart(string[] args)
  {
    _serviceLogic.Start(args);
  }

  protected override void OnStop()
  {
    _serviceLogic.Stop();
  }
}

When you start the executable without arguments, it will try to run as a Windows Service. This is recommended because when installed as a service, by default it will also be started without arguments. Unless specified otherwise in its image path of course, so it is possible to reverse this behavior by installing it for example using a “/RunService” parameter.

Now when providing the “/D” or “/DEBUG” flag, the instantiated MyServiceLogic with have its Start() method called. You can set the command line arguments by right-clicking the console app project in Visual Studio, selecting Properties and clicking the Debug tab:

Command line arguments

Note: the call to myServiceLogic.Start() passes the remainder of the command line arguments (omitting the “/D[EBUG]”), so your service logic can also support other parameters. A starting service does not receive its commandline arguments at OnStart() nor in Main() though, the parameters you receive there are those entered in the “Start parameters” set in the Properties window of the service through the Services management console.

Installing the service

This debuggable service can’t be installed yet, as running installutil.exe on the assembly will show the error “No public installers with the RunInstallerAttribute.Yes attribute could be found”.

It can also be useful to make the service self-installing, so you won’t have to rely on installutil.exe being present on the target machine. The following code enables a service to install itself, after adding a reference to the .NET assembly System.Configuration.Install:

[System.ComponentModel.DesignerCategory("Code")] // Prevent double-clicking the file to open designer mode.
public class CustomServiceInstaller : Installer
{
  public static void Install(IServiceLogic service)
  {
    var installer = GetInstaller(service);
    installer.Install(new Hashtable());
  }

  public static void Uninstall(IServiceLogic service)
  {
    var installer = GetInstaller(service);
    installer.Uninstall(null);
  }

  public CustomServiceInstaller(IServiceLogic service)
  {
    ServiceProcessInstaller serviceProcessInstaller =
               new ServiceProcessInstaller();
    ServiceInstaller serviceInstaller = new ServiceInstaller();

    // Service Account Information
    serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
    serviceProcessInstaller.Username = null;
    serviceProcessInstaller.Password = null;

    // Service Information
    serviceInstaller.StartType = ServiceStartMode.Automatic;

    // Info from ServiceLogic
    serviceInstaller.ServiceName = service.ServiceName;
    serviceInstaller.DisplayName = service.ServiceDisplayName;
    serviceInstaller.Description = service.ServiceDescription;
    
    this.Installers.Add(serviceProcessInstaller);
    this.Installers.Add(serviceInstaller);
  }

  private static TransactedInstaller GetInstaller(IServiceLogic service)
  {
    var serviceAssembly = service.GetType().Assembly;

    string[] commandLine = new[] { String.Format("/assemblypath={0}", serviceAssembly.Location) };
    string logFile = string.Format("{0}.installlog", serviceAssembly.FullName);

    InstallContext installContext = new InstallContext(logFile, commandLine);
    TransactedInstaller transactedInstaller = new TransactedInstaller();

    transactedInstaller.Installers.Add(new CustomServiceInstaller(service));
    transactedInstaller.Context = installContext;

    return transactedInstaller;
  }
}

The calling code now looks like this:

public static class Program
{
  public static void Main(string[] args)
  {
    // Instantiate the service logic.
    var myServiceLogic = new MyServiceLogic();

    // No arguments? Run the Service and exit when service exits.
    if (!args.Any())
    {
      ServiceBase.Run(new CustomServiceBase(myServiceLogic));
      return;
    }

    // Parse arguments.
    switch (args.First().ToUpperInvariant())
    {
      case "/D":
      case "/DEBUG":
        StartService(myServiceLogic, args);
        break;
      case "/I":
      case "/INSTALL":
        InstallService(myServiceLogic);
        break;
      case "/U":
      case "/UNINSTALL":
        UninstallService(myServiceLogic);
        break;
      default:
        PrintUsage();
        break;
    }
  }

  private static void InstallService(IServiceLogic myService)
  {
    CustomServiceInstaller.Install(myService);
  }

  private static void UninstallService(IServiceLogic myService)
  {
    CustomServiceInstaller.Uninstall(myService);
  }

  /// <summary>
  /// Passes the remainder of the commandline arguments to the ServiceLogic and starts it.            
  /// </summary>
  /// <param name="serviceLogic"></param>
  /// <param name="args"></param>
  private static void StartService(IServiceLogic serviceLogic, IEnumerable<string> args)
  {
    serviceLogic.Start(args.Skip(1));
  }

  private static void PrintUsage()
  {
    Console.WriteLine("Usage:");
    Console.WriteLine();
    string exeName = string.Format(" {0} ", Path.GetFileName(Assembly.GetEntryAssembly().Location));
    Console.Write(exeName + " /D[ebug]\tStart the service logic");
    Console.Write(exeName + " /I[nstall]\tInstall the executable as Windows Service");
    Console.Write(exeName + " /U[ninstall]\tUninstall the Windows Service");
  }
}

Third-party

You don’t want to reinvent the wheel. Using above code, I showed why and how you would do this. There are various libraries that encapsulate this behavior so you don’t have to write and maintain it anymore. To name a few:

Each of these and other libraries have their own mindset. Some are config-oriented, some use properties and others rely on attributes you have to place in your code. There are libraries that come with a user interface to start and stop the service being debugged.
Most or all of these libraries are also available as NuGet packages.

Posted in Tech | Tagged , , , | Leave a comment

Stack Overflow reference questions

In this post I keep a list of questions and answers I frequently link to on Stack Overflow.

.NET

NullReferenceException

What is a NullReferenceException and how do I fix it?

HTTP 500 – Internal Server Error on IIS

How to find the underlying cause for an HTTP 500 – Internal server error in IIS?

Localization of ASP.NET MVC Unobtrusive Validation

MVC 3 jQuery Validation/globalizing of number/decimal field

Change Visual Studio New Class Template

How do I edit the Visual Studio templates for new C# class/interface?

IPC mechanisms in .NET

IPC Mechanisms in .NET – Usage and Best Practices

Enable WCF Tracing

How to turn on WCF tracing?

 

PHP

Enable Error Reporting in PHP

How to get useful error messages in PHP?

Posted in Tech | Leave a comment

Posting sortable form items to an MVC controller

I wanted to allow the user to edit a list of items while also enabling the user to sort them, and to post that back in a meaningful way without parsing on the server side. This does the trick:

public class SortableModel
{
  public List<CustomItem> CustomItems { get; set; }
}

public class CustomItem
{
  public int Order { get; set; }
  public string Description { get; set; }
}  

var model = new SortableModel
{
  CustomItems = new List<CustomItem>
  {
    new CustomItem { Order = 0, Description = "Test 1"},
    new CustomItem { Order = 1, Description = "Foo 2"},
    new CustomItem { Order = 2, Description = "Bar 3"}
  }
};

View:

<script src="@Url.Content("Scripts/jquery-1.9.1.js")"></script>
<script src="@Url.Content("Scripts/jquery-ui-1.10.1.js")"></script>
<script type="text/javascript">
  $(function () {
    $("#sortMe").sortable({
      stop: function (event, ui) {

        $("#sortMe li").each(function (index, element) {
          // find the hidden input in each <li> and set it to its current index, according to the DOM
          var hiddenInput = $(element).children(".order").first();
          hiddenInput.val(index);
        });
      }
    });
  });
</script>
@using (Html.BeginForm())
{
  <ul id="sortMe">
  @for (int i = 0; i < Model.CustomItems.Count; i++)
  {
    <li>@Html.HiddenFor(m => m.CustomItems[i].Order, new { @class = "order" }) @Html.TextBoxFor(m => m.CustomItems[i].Description) <span>Drag me!</span></li>
  }
  </ul>
  <input type="submit" value="Save" />
}

Now my action can accept a SortableModel parameter, where we can loop through the list of CustomItems in order to determine their order!

[HttpPost]
public ActionResult CustomFieldsForPort(SortableModel model)
{
  // do your thing with model!
	
  return View(model);
}

Up next: adding and deleting items.

Posted in Tech | Leave a comment

Controller injection with Unity under ASP.NET MVC 4

A lot of different manuals exist on the web explaining various portions of MVC unit testing, Entity Framework mocking and Inversion of Control (IoC) using Unity as dependency injection container. In this and hopefully future posts I’ll try to sew together the bits I found on various places.
Continue reading

Posted in Tech | Tagged , , , , , | 1 Comment

An idea for multilingual webpages: the Content-Languages response header

Much content on the web is provided in multiple languages. Think about corporate websites, Wikipedia and various sites running on popular content management systems. The issue I would like to address is the display and selection of the languages the content is available in.
Continue reading

Posted in Tech | Leave a comment

Using the WebClient class – with cookies!

Contrary to the somewhat crude HttpWebRequest class, the WebClient allows the developer to easily download and upload data and strings from and to webservers.

The rough edges of the HttpWebRequest class make developers jump to the WebClient (or HttpClient, since .NET 4.5) to significantly increase the ease-of-use. The WebClient has one drawback: it doesn’t support cookies!

Continue reading

Posted in Tech | Tagged , , , , | Leave a comment

Configuring a shared packages directory for NuGet and automatically downloading packages

This entry is also available in Dutch.

The ever so popular Visual Studio extension named NuGet enables the developer to easily install packages from within the development environment. NuGet packages contain populair and less known libraries, like log4net, jQuery and Entity Framework.

Continue reading

Posted in Tech | Tagged , , , | 2 Comments

Sockets and protocols: exchanging messages. Using bytes.

There’s also a Dutch version of this article available.

When two applications wish to communicate over an (inter)network, sockets quickly come into play. Nowadays sockets are delivered by almost every operating system, in the form of an API that enables the developer to easily transfer data through a local network or over the internet to another machine.

Continue reading

Posted in Tech | Tagged , , | 4 Comments

Remove Origin advertisements

Do you love the Sims and FIFA advertisements popping up after logging in to Origin when you’re about to play some Battlefield 3? Or even the Premium ads while you already have bought Premium? I don’t, so inspired by this post I contacted EA support and asked if there’s any way to disable displaying the advertisements. Their solution: reboot your PC. Luckily, I found a real solution:

Run Notepad (or the slightly better alternative) and open the file %appdata%\Origin\Settings.xml, and locate the following lines:

<Setting key="PromoBrowserGameFinishedLastShown" type="2" value="xxx"/>
<Setting key="PromoBrowserOriginStartedLastShown" type="2" value="xxx"/>

Change the values of xxx to 9999999 and the ads will disappear. :)

Posted in Tech | Tagged , , | 4 Comments

Remotely viewing detailed error pages in IIS

When deploying applications or services to IIS one can sometimes run into errors that haven’t been foreseen during development. Of course, with appropriate logging you can quickly identify the source of the problem, but when your site lacks this functionality you’d love to see the same detailed exception information as you see while you’re developing the application.

Continue reading

Posted in Tech | Tagged , , | Leave a comment