I have been spending some time thinking about how I could allow a user to interact with a custom Windows service that I had written. I want to allow the user to alter the configuration of the service and to receive feedback on the different processes occurring inside this service. In the past I had written a Windows application that used TCP/IP to communicate with the service. To me this seemed a bit much since I now have to maintain not only a Windows service but also a Windows client application… not to mention all of the work to add the TCP/IP communication layer. I want something simple to deploy, simple to manage and of course simple to code.
In my search for the ultimate solution I came across a nice little gem in the .NET 2.0/3.0 framework that I had not previously not seen; the HttpListener class. This class is amazing! Before jumping to far into this you need to understand that the HttpListner class only works for Windows XP SP2 and Windows Server 2003. I have not tested it on Vista but I am guessing that it would also work under that operating system; you can always use the HttpListner.IsSupported static property to check if the run time operating system supports this class.
With the HttpListener class I can easily have my Windows service accept HTTP connections and respond to them appropriately. This means I can have a simple HTML UI for my Windows Service without any IIS configuration or complex coding.
The HttpListener class can handle connections in either a synchronous or asynchronous manner. In my Windows service I have decided to use the asynchronous method so that my service can continue to operate without the need for me to write any complex threading code. Therefore I utilized the BeginGetContext and EndGetContext methods of the HttpListener class.
The BeginGetContext method accepts two parameters; a callback delegate and a state object. The callback delegate is pretty self-explanatory but you may wonder what the state object is. The state object is any object that you want passed to the callback method. I would believe that most of the time you would want to use the instance of your HttpListener class as the state object so you have access to the HttpListener class methods and properties in your callback.
Using the HttpListener class is simple. Below is a quick checklist that will get you started.
Starting the HttpListener
1. Verify that the user’s OS supports HttpListener by using the IsSupported static property.
2. Create an instance of the HttpListener class.
3. Specify the prefixes that the HttpListener will respond to. For example http://blog.mikehacker.net:8080
4. Start the listener using the Start method.
5. Call the BeginGetContext method passing in the callback delegate and the instance of HttpListener created in step 2.
Responding to connections
1. Create a new method with the name used for the delegate in the BeginGetContext call. This method should accept an IASyncResult parameter.
2. Retrieve the HttpListener instance from the IASyncResult parameter using the get_AsyncState method.
3. Use the HttpListener object from step #2 to access the context, request and response objects.
4. Craft your HTML output string and then convert it to a ubyte array.
5. Specify the length of the output HTML ubyte array in the HttpListener’s response object. Do this using the set_ContentLength64 method.
6. Use the HttpListener’s response object’s get_OutputStream method to access the response data stream.
7. Write your HTML ubyte array to the output stream.
8. Call the BeginGetContext method so that the listener can respond to the next connection.
Ok… so starting the HttpListener sounds simple but the responding to connections does appear to be a bit more complicated. In a future post I will show the code for creating a simple asynchronous HttpListener. Stay tuned for more…. J