Continued from “Building a Windows Service – Part 6: Adding resources and event logging

So let’s recap our goals for this project:

  • Building a service that can also be used from the console
  • Proper event logging of service startup/shutdown and other activities
  • Allowing multiple instances by using command-line arguments
  • Self installation of service and event log
  • Proper event logging of service exceptions and errors
  • Controlling of start-up, shutdown and restart options
  • Handling custom service commands, power, and session events
  • Customizing service security and access control

Yep, we are on the mark there and have demonstrated most of these in the past few posts. The goal not stated directly has always been to to create a new project template. We had a bit of cleaning up to do before we could deal with that. I’m not going to cover this clean up in the same level of detail as before, but here are a few words about how this has changed from the previous posts:

  1. I’ve added an application icon and manifest. This brought to light that the generator for the win32 resources was not preserving the manifest, nor was it correctly locating the icon when I moved the resources file. To get this working I’ve built a custom version of the CSharpTest.Net.Generators executable.
  2. For all the good it does, I’ve added an UnhandledException event listener on the AppDomain to attempt to log the exception. As you probably know this is unreliable at best ;)
  3. I’ve split all the resources into three parts, messages that are written, exceptions that log, and normal non-logging string resources. These have been to a Resources folder and all resource/event specific stuff is now located there.
  4. The remainder of the service stub class, “ServiceImplementation” has been filled out to include power and session events, custom commands, etc. The appropriate logging and plumbing has been introduced into the ServiceProcess class to support these new methods.
  5. There are a couple of other small changes and always bugs, and I’ve had to fix a few from the previous posts.

The end result is a clean easy to use project template for Visual Studio 2008. This can easily be upgraded to 2010 if you desire. The project is currently using the 2.0 Framework to allow the greatest flexibility, but obviously once you create the project from the template it can be changed.

zip Download the Visual Studio Service Project Template
To use the template place it in the following path for 2008:
%UserProfile%\My Documents\Visual Studio 2008\Templates\ProjectTemplates\Visual C#

Once installed, create a new project, locate the template “ServiceTemplate” and create a project. Since the project name is used heavily throughout the template you should avoid names that contain non-alpha-numeric text or are longer than 64 characters. You can always rename the project file, assembly, and default namespace later, but start with a simple name. After the project has been created there are two things to do from the command line. Assuming a working directory at the root of the project the following commands should be run:

C:\Projects\MyService> Tools\CmdTool.exe register
C:\Projects\MyService> Tools\CmdTool.exe build MyService.csproj
Generating C:\Projects\MyService\Resources\Exceptions.resx
Generating C:\Projects\MyService\Resources\FormatString.resx
Generating C:\Projects\MyService\Resources\Messages.resx

Now you can build and run the project with the ‘install’ command and away you go. Modify the ServiceImplementation class to provide the service implementation. Adjust the default IsolateDomain, and ShadowCopy settings to your desired defaults. Don’t forget if you want to debug service start-up you can run the command “start {servicename} DEBUG!” and, if the service is not running, a debug break-point will be triggered.

It’s not often I have to create a windows service, yet each time it takes me several days to work all this out. I hope this will save you some time as well, enjoy.

PS: If you’ve missed any of the previous posts, here they are: