Once in a blue moon I’m tasked with a project whose requirements call for a long-running (or periodically running) application that needs little in the way of user interaction. As I’ve a small cadre of .NET developers and plenty of Windows OS surrounding me, one solution has been to implement a Windows Service.
Creating a Windows Service project in Microsoft Visual Studio 2010 takes all of three or four mouse clicks. What isn’t immediately clear, and what will serve as the topic for this entry, is:
- How to get your Windows Service to run every X seconds/minutes/hours (on a timer)
- How to make your Windows Service installable
- How to read application settings from a .CONFIG file
- How to perform real-time debugging upon your Windows Service
Excited? All right, let’s roll!
How to get your Windows Service to run every X seconds/minutes/hours (on a timer)
In order to get your new Windows Service to run periodically, we make use of the System.Timers.Timer object. The code fragment below illustrates how to add the basic start, stop and timer objects and classes to the automatically-created main file, Service1.vb. I hope it’s self-explanatory.
Public Class Service1 Public thisTimer As System.Timers.Timer Public IsRunning As Boolean ' This automatically-created subprocedure contains code you want run when the service is started. Protected Overrides Sub OnStart(ByVal args() As String) ' Set initial variable values. Me.IsRunning = False ' Create and start a timer that checks every 20 seconds. thisTimer = New System.Timers.Timer() thisTimer.Enabled = True thisTimer.Interval = 20000 thisTimer.AutoReset = True AddHandler thisTimer.Elapsed, AddressOf thisTimer_Tick thisTimer.Start() End Sub ' This automatically-created subprocedure contains code you want run when the service is stopped. Protected Overrides Sub OnStop() End Sub ' This subprocedure is of our own creation, used to store code we want this service to actually execute. Public Sub DoNextExecution() SyncLock Me thisTimer.Stop() ' Another execution cycle begins. thisTimer.Start() End SyncLock End Sub ' Each time the timer completes an interval, it executes the code found within this subprocedure. Private Sub thisTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) DoNextExecution() End Sub End Class
I should add that, like you, I was initially concerned about the CPU utilization of using a timer in this fashion. I am happy to report that the Windows Service does idle while no activity except for the timer are running.
How to make your Windows Service installable
The Windows Service requires extra code to be able to be installed onto a Windows machine. Start by adding a new item to the project of the type Installer Class. Following the lead of others, I typically name this class ProjectInstaller.vb. Then right-click on the new class and select View Designer mode.
Visual Studio 2010 unfortunately does not have the controls you require listed in the toolbox by default, so we’ll need to add them to it. Do this by opening the Tools menu and selecting Choose Toolbox Items… In the .NET Framework Components tab, sort by Namespace. Add System.ServiceProcess.ServiceInstaller and System.ServiceProcess.ServiceProcessInstaller and press OK.
Let’s configure the first item, the ServiceInstaller:
- Under the toolbox section Visual Basic PowerPacks, drag a ServiceInstaller into the ProjectInstaller.vb design window. Right-click on it and select Properties.
- Verify that the Parent property is set to ProjectInstaller.
- Change the Service Name property to what you want the service to be called within the list of services in Windows.
- Change the StartType property using the drop-down to Automatic.
Now configure the second item, the ServiceProcessInstaller:
- Under the toolbox section Visual Basic PowerPacks, drag a ServiceProcessInstaller into the ProjectInstaller.vb design window. Right-click on it and select Properties.
- Change the Parent property to ProjectInstaller.
- Change the Account property to LocalSystem.
That’s it – save ProjectInstaller.vb to disk. You can now use the InstallUtil.exe program to actually install your new Windows Service to a machine to begin use of it.
How to read application settings from a .CONFIG file
Nearly every application has environment settings that rarely change but, when they do, need to be easily and quickly modified. A Windows Service project provides this functionality through .CONFIG files. There are two key pieces of knowledge needed to use a .CONFIG file with a Windows Service:
- The .CONFIG file must reside in the same directory as the .EXE that is compiled.
- The .CONFIG file must be named identically to the .EXE file, with a second extension .CONFIG appended to the end.
Thus, if I have compiled SampleService.exe, I create and save a file called SampleService.exe.config to the same directory.
A Windows Service is again by default not set up to use .CONFIG files – but enabling that functionality is a three-click process:
- Right-click References in the project’s Solution Explorer and select Add Reference…
- Add a reference to System.Configuration.
You may now refer to application variables from the .CONFIG file in this manner:
The corresponding value would be written in the .CONFIG value as:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="DirectoryLogs" value="E:\Database\logs\MigrationService" /> </appSettings> </configuration>
How to perform real-time debugging upon your Windows Service
One of the most fantastic features about all of the Visual Studio IDEs is the integrated debug tools. Most people are familiar with the method in which you begin step-by-step debugging of a web application: Start debug mode and navigate to the page using your Web browser.
Debugging a Windows Service is nearly as straightforward: Compile your Windows Service and install it as a service on your local machine (in debug mode). Then, with Visual Studio 2010 still open and using the exact same copy of the code as was just installed:
- Under the Debug menu, select Attach To Process…
- Near the bottom of the window, select Show processes in all sessions.
- Left-click the EXE you compiled to be run as the Windows Service in the list (it might help to sort by Process). Click Attach.
Now, if you place breakpoints at places in your functions that you know will be executed, you’ll be able to take control of the service as it continues to execute.
That covers all of our topics, from getting your Windows Service to periodically execute code to how to bug your service in real time. If you’ve got any comments or questions please leave a comment and I’ll do my best to clarify anything that may be unclear.