May 7th, 2010

Debug Windows services in C# using reflection

[This example is for .NET 3.5 and Visual Studio 2008]

I recently had to fix a bug in a Windows service written in C#. Unfortunately, Windows services are not straightforward to run in debug mode. This led me to try two solutions that I found lacking. I ended up using a relatively simple and flexible method involving reflection. I will provide some sample code below to help you use this in your own projects.

Option 1: the Microsoft way (inconvenient)

Microsoft’s official recommendation is to install the service and then attach the debugger to the service. While this is the best way to monitor a live service, it has two drawbacks when it comes to development: 1) you need to reinstall the service each time you want to debug, and 2) “you cannot debug the code in the service’s OnStart method this way”. Note that Microsoft does offer a workaround for the latter problem, though I find it to be rather inconvenient:

[...] create a temporary second service in your service application that exists only to aid in debugging. You can install both services, and then start this “dummy” service to load the service process. Once the temporary service has started the process, you can then [...] attach to the service process.

After trying this method, I ended up getting frustrated by the extra work involved and chose a simpler, but less maintainable, solution.

Option 2: run the service as an application (unmaintainable)

What ended up working for me (for a while, at least) was converting the project into a console application, with the service code being called from Main(). I successfully used this method to find the cause of the error and test my fix. I also used this method to make enhancements to the service.

However, it was only when I was making frequent check-ins that I spotted my problem: it took effort to make sure that I kept the repository’s version as a service and my own version as an application. It shouldn’t take that much effort to keep code synchronized.

So, while this method allows you to debug a service without first installing it, as well as debug the OnStart method, it doesn’t make for a maintainable solution. After learning about reflection, I found a better way.

Option 3: writing a test application using reflection

This method is based on reflection’s ability to invoke non-public members from outside of the target application. The basic idea is to create a second application that initiates the service.

Here’s how you can set this up for yourself.

First, create a Windows Service project. Visual Studio will automatically generate some code for you. Note the OnStart and OnStop methods, inherited from ServiceBase. These get called by Windows when the service is started and stopped, respectively; you will need to call these methods when you simulate running the service.

using System;
using System.ServiceProcess;

namespace TestableWindowsService
{
  public partial class Service1 : ServiceBase
  {
    public Service1()
    {
      InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
    }

    protected override void OnStop()
    {
    }
  }
}

Once your service is set up, create a new Console Application in the same solution. You will need to add a reference to the service project, as well as a reference to System.ServiceProcess (available under the .NET tab in the Add Reference… screen).

There isn’t much code you have to write to simulate calling the service, but it’s worth explaining.

Service1 service = new Service1();

Initiate the service so we can call its methods.

Type service1Type = typeof (Service1);

This is the key to reflection. Once we have the Type for the class, we can use reflection to access its methods and properties at runtime.

MethodInfo onStart = service1Type.GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Instance);

Here we use the GetMethod method to search for the method we want. The BindingFlags are important because OnStart is an instance method that is protected. Setting these flags ensures that these types of methods are included in the search. If the method isn’t found, null is returned.

onStart.Invoke(service, new object[] {null});

This is where we actually call the method. The method is called using the service object created above. The second argument to this method is the string[] parameter required by OnStart. Note that this cannot be set to null if there is a parameter in the method signature.

At this point, we have effectively started the service. If there is any code in your service’s Program.Main method that is supposed to run, you would call that now. Note that you can’t actually call the Program.Main method because it will try to start the service, which you can’t do from within Visual Studio.

MethodInfo onStop = service1Type.GetMethod("OnStop", BindingFlags.NonPublic | BindingFlags.Instance);
onStop.Invoke(service, null);

This code will stop the service. Since OnStop doesn’t have any parameters, null is used for the second argument. Depending on how your service is configured, you may not actually need to call this (since the TestApplication will kill the service anyway at this point).

using System;
using System.Reflection;

namespace TestableWindowsService
{
  class TestProgram
  {
    static void Main()
    {
      Service1 service = new Service1();

      Type service1Type = typeof (Service1);

      MethodInfo onStart = service1Type.GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Instance);
      onStart.Invoke(service, new object[] {null});

      MethodInfo onStop = service1Type.GetMethod("OnStop", BindingFlags.NonPublic | BindingFlags.Instance);
      onStop.Invoke(service, null);
    }
  }
}

When you build and run the test application in debug mode, you will be able to step through your service code without going through the trouble of installing the service and attaching the debugger.


June 30th, 2009

How to close the last/only tab in Firefox 3.5

I recently downloaded the latest version of Firefox. I quickly discovered that one of my favourite features was gone: the ability to close a tab if it’s the only one open.

It’s turns out that the feature isn’t missing; it’s just no longer enabled by default. I figure this makes sense since a fresh install of Firefox doesn’t show the tab bar at all for a single tab.

Anyway, here’s how to do it, just so you don’t have to mess around with the options to figure it out (like I did):

  1. Open about:config.
  2. Set browser.tabs.closeWindowWithLastTab to false.

And that’s all! Back to “normal” browsing.

EDIT: Looks like I beat mozillaZine by about 4 minutes on this. They now have a longish thread discussing this exact topic.


June 15th, 2009

Trusting your users is hard for you, but good for them

Default options should handle the most common, most trustworthy case.

Gmail got this right when they stopped asking for confirmation for users’ actions and started allowing people to undo them instead. For example, most of the time, I am sure I want to trash that email, so asking for confirmation does nothing for me; my default action becomes to auto-confirm, since it’s what I do most often. Ben Bryant has a good post on how trust worked for Wikipedia. And to quote Neil Davidson on avoiding the real problems: “don’t create rules for the many based on the sins of the few”.

When I built the prototype for my cell phone bill analysis tool, I had an item pretty high up on my list of core features to have user accounts. When I got to it, I titled my head to the side and let out a nice long “Hehhhnh?”. I realized that it really didn’t make much sense. If people wanted to come and try the service, having to register is a pain. I can’t even list off the apps – free or paid – that I wanted to try out once but stopped when I had to register. Seriously, it’s really, really annoying.

So I asked myself: “Why would people want to register?” The only answer I could come up with was that they might want to save their bill data and come back at a later date. I figured most people wouldn’t be doing that to start, so user accounts dropped priority, and I instead implemented persistent temporary sessions.

Apparently, Jason Kester feels the same way:

Our stated goal with Twiddla is to get the hell out of your way so that you can get some work done. We’ve taken that idea so far that most of our users will never see a login screen of any description. Some might not ever know they’ve used Twiddla at all, since we keep our Logo hidden away in the corner where it’s not in your way.

That’s a great example of putting your users first. Registering for a service is a hassle for the user, and that’s something that’s true whether there’s a good reason for registration or not. Maybe capturing a user’s information helps you market to them down the line. Maybe capturing a user’s information makes it easier for you to personalize the user’s experience. It doesn’t matter though. It’s not your choice. It’s the user’s choice.

And respecting a user’s choice is a great way to get them to trust you with their money.


May 13th, 2009

Grow great software without getting hung up on the past

Smart people can invent solutions to problems you don’t actually have yet. The problem is, it’s easy to think of problems you don’t have yet. Stopping to solve them all now is a recipe for paralysis.

– Chip Morningstar, Smart People Can Rationalize Anything

It’s important to focus on your current difficulties. And if you don’t have a current difficulty, pick any of your brilliant ideas and solve them in the simplest way first: with people. At MeshU 2008, Reg Braithwaite left me with some great advice: don’t automate what you haven’t already done manually.* And I hope I got that right, because he’s a smart guy and it’s stuck in my head now. What I do know is that anything you can do to increase your understanding of a problem will help you formulate a solution.

But you can’t really solve problems that don’t exist, because only problems have solutions – the absence of a problem necessarily implies the absence of a solution. Still, even the simple solutions of simple problems tend to reveal additional simple problems.

Here’s a real-world example. Several years ago, our developers designed a poll widget for our web sites. At the time, they didn’t have a semblance of the manual effort required to insert/delete/update poll questions. So they didn’t solve for it, and this was a very rational decision at the time, because it wasn’t a problem then. However, when it did manifest itself as a problem, they didn’t update their assessment of possible solutions. That’s why it’s important to revisit solutions over the course of their respective lifetimes; you need to keep solving the right problems while throwing away inadequate solutions.

It’s easy to neglect old features in light of new and exciting features, but that’s how projects get bloated to the point where anyone who touches the code gets this burning desire to just rebuild it from scratch.

Most people have a vague notion of the fact that new things get old, but it’s much rarer to find people who understand that old things get older. It’s not a binary definition. Things aren’t either “new” or “old”. They have an age that can be measured in continuous time units. It’s like how on the books, your company’s assets depreciate in value over time. That new widget-maker your company bought last week will have a different value after 4, 8, 15, 16, 23, or 42 years. Eventually, the machine itself has no value, but at any point in the interim, it does still have at least a bit. Accountants will take a look every year during tax season and advise the appropriate stakeholders that they need a new way to make widgets. And so a new machine will be purchased and the cycle starts all over again.

Software is the same way. Certain features depreciate in value over time. Eventually, those features no longer deliver any value to the end user and they become more costly to maintain than the benefit they deliver. That’s probably one of the best reasons to use a modular design that won’t break when you remove a feature.

But every project team has a different way of determining when a feature or product has lost its value. Ruby on Rails decided to *6 components after two years. On the other hand, Intel went on adding new features to their x86 chip for over 30 years without removing extraneous features: “The 8086 was the first processor in the x86 family launched in mid 1978. All future members are backwards compatible with it.”

Features – and feature sets – are built up from an initial spec, regardless of what methodology you follow. What’s important is how often you revisit those initial specs and evaluate them in light of the true, underlying requirements of the project, which themselves necessarily change over time. I agree with Jurgen Appelo’s concept of growing software rather than building it, although he’s wise enough to not claim it as his own :oP.

We also talk about building software. And (in many cases) that’s incorrect too. What we build are lines of code, design documents, and compiled assemblies. What we grow are user interaction, data repositories, social networks, and (for the systems that I grow myself) extensive bug reports and issues. The sum of all that we call software systems.

Software is versatile. It’s programmable (of course). More importantly, it’s re-programmable. To throw away that kind of power by refusing to acknowledge the changing nature of users, developers, business owners, and all their various, also-changing needs is a fruitless exercise.

Focus on delivering the best possible value regardless of your past decisions.

*The corollary is that if you’ve done something manually and it can be automated, do so.


April 23rd, 2009

Using a Database to Store Transient Data

The Motivation

Off The Clock was initially built to analyze phone usage data pulled from a database, but I also wanted to be able to analyze transient data. Storing transient data in a database is a great way to accomplish this; it allows the analysis code to treat the transient data as if it were persistent, thus avoiding unnecessary duplication of code and providing a consistent analysis.

The Solution

Storing transient data in a database was actually quite simple. The first step was to understand that all of the user’s data has to be tied to their current session. For all intents and purposes, their current session acts like their “account”. That means that the session id works as the account id.

With that in mind, I decided that until a user registered, I could just store the relevant data in the database along with the current session id, which is automatically generated by PHP.

So, the corresponding table would look a little like this:


CREATE TABLE usage_data
(
  call_id INT NOT NULL PRIMARY KEY,
  call_duration INT,
  the_session_id TEXT
)

And I can insert the values into the database like this:


mysql_query("
  INSERT INTO usage_data
    (call_duration, the_session_id)
  VALUES (" .
    "'" . $callDuration . "'," .
    "'" . session_id() . "'" .
  ")"
);

With this design, the code that fetches and reports on the data can match the current session id with the session id in the database, and report only on data uploaded during the current session. Every query just needs to have the current session id in the WHERE clause, like so:


mysql_query("
  SELECT call_duration
  FROM usage_data
  WHERE the_session_id = '" . session_id() . "'" .
  ")"
);

As an extra bonus, the code doesn’t need to be duplicated and re-written to report on one-off data sets. This also means that a user can upload and get stats and multiple phone bills within a single session, without having to register for an account.

In short, this allows the tool to function in demo mode by default.

The next step is to determine the best way to allow a user to save their session by way of registering for an account.