Monday, May 19, 2008

Creating a Windows service in .NET

much as i would like to, this isn't a real tutorial about creating a Windows service in .NET. there are lots of excellent tutorials in that regard. this is just to highlight some problems i had recently when i created a service. usually, the service sits in the background, waiting for "something to happen", maybe a client connects, a timeout goes off, and all that. my service is a time-based service that performs certain actions when a timer goes off.

to get my service doing some "real" work, i used the System.Timers.Timer class, which has the Elapsed event, which calls a callback method when the timer fires. here's a caveat: the callback for the Elapsed event suppresses all exceptions in .Net 2.0 and lower (i can't categorically say that the behaviour isn't the same in higher versions). forget processing unexpected exceptions in your callback - they'll get supressed. and you may end up like me: after putting in a full day at work, spending the night there, and putting in another full day, you're at the client's and the service runs but doesn't do anything.

my fix? in my callback, i start a separate thread. the thread takes responsibility for doing the processing that was in my callback, and i once again can see what exceptions occur in my processing. by the way, design your tables so none of your fields are allowed the NULL value in .Net. use sensible defaults instead of NULL, becaue you never know when you'll get a System.DBNull object that isn't automatically converted to null. later, then!

Edit: when services run - irrespective of where the executable actually is - the working directory is always C:\WINDOWS\System32. that can be a problem if you access to files residing in the same location as the executable, especially if you don't know where the service executable is (if you think that is strange, think again: you - or someone else - could create an installer that allows the user customize the location of the install). if you need to get access to the executable's location, you can do:

string basepath = System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase;
System.IO.Path.GetDirectoryName(basepath);
this will retrieve the path in a format such as file:///C:/..., so you'll need to trim off the beginning of the string returned.

i used SharpDevelop for creating my service, as creating the service from scratch (Visual C# 2008 Express) or tusing an application template (Visual Studio 2008) gave me problems when trying to install the service using installutil. SharpDevelop integrates with FxCop, a code analysis tool developed by Microsoft. running FxCop on my executable showed me some things i'd never really noticed before, such as using string.IsNullOrEmpty(variable) instead of if ((variable == string.Empty) || (variable == null)) to check if a string was empty or null.

Blogged with the Flock Browser

No comments: