We don’t build many Windows Service applications any more these days, but every once in a while, the need for one comes around. With Visual Studio 2010 now the mainstay of our tool set, let’s look at how you accomplish the mission using this tool.
-
Launch Visual Studio 2010.
-
From the Start Page, click "New Project". If the Start Page isn't visible, you can view it via the View/Start Page menu.
-
-
If you have the .NET Framework 4.0 installed, Visual Studio will default to that as the target. Since my specific application is targeting a SharePoint server, I'll set the framework target to .NET Framework 3.5 instead.
-
From the Installed Templates list, expand "Visual C#" (or VB.NET if you're still using it).
-
Select the "Windows" section in the left pane.
-
Available templates are populated in the right pane. Select "Windows Service" in the right pane.
-
Provide a Name for your project. In my case, the names are getting very long with namespaces included so I'm saving my project in a local C:\CODE folder instead of under My Documents.
-
Once you've picked the folder location, click "OK" to create the project.
-
-
By default, VS will create a service named "Service1.cs" for us.
-
In the Solution Explorer, right click the "Service1.cs" file.
-
On the popup menu, click "Rename".
-
-
VS will prompt you for reference renames. Click "Yes".
-
-
Enter the name of the new service and press Enter to complete the rename. As you can see, I renamed my service to "RefreshBloggerRatings.cs".
-
-
Now we need to edit the service class. In the Solution Explorer, double click the service class name.
-
The canvas fills the main edit area. Time to add some components.
-
Expand the Toolbox.
-
Expand the Components section.
-
Since our service runs without a user interface, we need some way to send messages to the system for tracking and/or debugging purposes. The
Event Log is most useful for this. Let's add the ability to write to the Event Log to our service.
-
Locate the EventLog control and drag it to your canvas.
-
-
By default VS will name the new control "eventLog1". Being the developer type that I am, I don't like default names so... you guessed it... I'm going to rename it.
-
In our case, I renamed the control to "RBREventLog".
-
-
Next we need to write some code for our service.
-
Right click on the canvas and click "View Code" or use the VS shortcut and just press F7.
-
-
You should now be looking at the C# source code for our service application. There's not much to it, but this is what you should have right now.
-
Code Snippet
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
namespace cjvandyk.WindowsServices.RefreshBloggerRatings
{
public partial class RefreshBloggerRatings : ServiceBase
{
public RefreshBloggerRatings()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
}
-
In the class constructor, underneath the InitializeComponent() method, we are going to add the code to initialize our Event Log. You can use the existing event log sources, but I like separating mine off onto it's own source. Modify the constructor method to look like this:
-
Code Snippet
public RefreshBloggerRatings()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("cjvandyk"))
{
System.Diagnostics.EventLog.CreateEventSource("cjvandyk", "cjvandyk.Log");
}
RBREventLog.Source = "cjvandyk";
RBREventLog.Log = "cjvandyk.Log";
}
-
Now that we have initialized our event log source, we can write to it.
-
Modify the OnStart() method to write to the log whenever our service starts as follows:
-
Code Snippet
protected override void OnStart(string[] args)
{
RBREventLog.WriteEntry("RefreshBloggerRatings() starting...");
}
-
Also modify the OnStop() method to do the same kind of thing thus:
-
Code Snippet
protected override void OnStop()
{
RBREventLog.WriteEntry("RefreshBloggerRatings() stopping...");
}
-
Now that we have our service startup and shutdown processes in place, we need to define a way for the service to actually do something. In this case, I want the service application to run daily and do some processing when it does. For the trigger, we'll be using a Timer.
-
Switch back to the canvas view of the app.
-
In the Components section of the Toolbox, locate the "Timer" control and drag it onto the canvas.
-
-
As before, I'm going to rename it from the default "timer1" to "RBRTimer".
-
-
Now right click the Timer control and select "Properties".
-
The property we are interested in is the "Interval".
-
The Interval value is in milliseconds so that's 1/1000th of a second. In order to have the timer trigger once daily we need to set it to 24 (hours) X 60 (minutes) X 60 (seconds) X 1000 (milli) or 86,400,000.
-
Set the value and press Enter.
-
-
Next we want to start and stop the timer when our service starts/stops.
-
Switch back to the Code View of our app and add to the OnStart() and OnStop() methods.
-
We want to enable and then start the timer when the service starts and inversely stop and disable the timer when the service stops. Modify the methods thus:
-
Code Snippet
protected override void OnStart(string[] args)
{
RBREventLog.WriteEntry("RefreshBloggerRatings() starting...");
RBRTimer.Enabled = true;
RBRTimer.Start();
}
protected override void OnStop()
{
RBREventLog.WriteEntry("RefreshBloggerRatings() stopping...");
RBRTimer.Stop();
RBRTimer.Enabled = false;
}
-
Now that our Timer triggers an event every day, we need to add the code to actually do something when the timer triggers.
-
In the Properties windows of the Timer, click the "Events" button. It looks like a little lightning bolt.
-
This switches the Properties window over so we can see the Event Handlers that are defined.
-
-
As you can see, the Timer control only has a single event available to it. The event is called "Tick".
-
You can tell that no method has been defined yet because there's none listed.
-
To the right of the Tick event, double click the white space.
-
-
VS will create the new method and bind it to the event. It will also switch to code view and allow you to edit the method now.
-
For now, I'm just adding a TODO item to the method, but this is where you would add your working code.
-
Code Snippet
private void RBRTimer_Tick(object sender, EventArgs e)
{
//TODO: Write the processing code here.
}
-
Switching back to the Properties view, you'll see the method bound to the event.
-
-
Our completed code base should now look like this:
-
Code Snippet
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
namespace cjvandyk.WindowsServices.RefreshBloggerRatings
{
public partial class RefreshBloggerRatings : ServiceBase
{
public RefreshBloggerRatings()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("cjvandyk"))
{
System.Diagnostics.EventLog.CreateEventSource("cjvandyk", "cjvandyk.Log");
}
RBREventLog.Source = "cjvandyk";
RBREventLog.Log = "cjvandyk.Log";
}
protected override void OnStart(string[] args)
{
RBREventLog.WriteEntry("RefreshBloggerRatings() starting...");
RBRTimer.Enabled = true;
RBRTimer.Start();
}
protected override void OnStop()
{
RBREventLog.WriteEntry("RefreshBloggerRatings() stopping...");
RBRTimer.Stop();
RBRTimer.Enabled = false;
}
private void RBRTimer_Tick(object sender, EventArgs e)
{
//TODO: Write the processing code here.
RBREventLog.WriteEntry("RefreshBloggerRatings() processing...");
}
}
}
-
ADD INSTALLERS
-
Switch back to the canvas view of the app.
-
Right click on white space on the canvas.
-
On the popup menu, click "Add Installer".
-
-
VS adds the ProjectInstaller components to the project.
-
From the design view of ProjectInstaller.cs, you'll notice two controls that were added. They are "serviceProcessInstaller1" and "serviceInstaller1".
-
-
As before, I'm renaming these.
-
Right click the "serviceProcessInstaller1" control and click "Properties" on the popup menu.
-
Change the name in the Properties pane. I decided to change my control to "RBRserviceProcessInstaller".
-
-
Right click the "serviceInstaller1" control and click "Properties" on the popup menu.
-
Change the name in the Properties pane. I decided to change my control to "RBRserviceInstaller".
-
-
Now you can modify the properties of the installer controls. These properties are useful for informing the administrator about what the service is.
-
Set the Description value to what you'd like it to be displayed in the Windows Services window.
-
The ServiceName is the name that is actually used in the Windows Services window.
-
You can also set the StartType.
-
-
Next we need to set the properties of the "RBRserviceProcessInstaller". This is where we tell Windows under which account to run the service etc.
-
We've selected "LocalSystem" which is a highly privileged account, basically a local admin, for our purposes.
-
-
Time to build our project.
-
In the Solution Explorer right click the project name and click "Rebuild".
-
-
ADD SETUP
-
Now that we know our service compiles, it's time to package and distribute it.
-
In the Solution Explorer, right click on the solution name.
-
On the popup, click "Add".
-
On the flyout menu, click "New Project".
-
-
In the Installed Templates pane, expand the "Other Project Types" section.
-
Expand the "Setup and Deployment" sub section.
-
Select the "Visual Studio Installer" option in the left panel.
-
In the right panel, select the "Setup Project" option.
-
Give the setup project a name and click "OK" to add it.
-
-
Right click the newly added setup project in the Solution Explorer.
-
On the popup menu, click "Add".
-
On the flyout menu, click "Project Output".
-
-
A modal window opens.
-
Select "Primary output".
-
Click "OK" to add the output to the setup project.
-
-
Your setup project should now look something like this:
-
-
Next we need to add a custom action to the setup project.
-
Right click the setup project in the Solution Explorer.
-
On the popup menu, click "View".
-
On the flyout menu, click "Custom Actions".
-
-
In the canvas pane, right click the "Custom Actions" section.
-
On the popup menu, click "Add Custom Action".
-
-
In the modal window that opens, double click "Application Folder".
-
-
Select the "Primary output from ..." option.
-
Click "OK".
-
-
Your Custom Actions should now look like this:
-
-
Time to build. Right click the setup project in Solution Explorer.
-
On the popup menu, click "Rebuild".
-
-
Ensure that the "Rebuild All succeeded" message appears telling us that all our project compiled successfully.
-
-
INSTALL
-
You can now distribute the setup files to the computer you wish to install on. installation is pretty easy.
-
Right click the setup project in Solution Explorer.
-
In the popup menu, click "Open Folder in Windows Explorer".
-
-
Navigate Windows Explorer to the Debug folder and you should see the setup files.
-
Double click "setup.exe" to install.
-
-
On the Welcome screen, click "Next".
-
-
On the Installation Folder screen, ensure the "Everyone" radio button is selected.
-
Click "Next".
-
-
On the Confirm Installation screen, click "Next".
-
-
On the Installation Complete screen, click "Close".
-
-
TEST
-
Open Event Viewer through Start/Control Panel/Administrative Tools/Event Viewer.
-
You'll notice the standard Windows event sources.
-
-
Now open Services through Start/Control Panel/Administrative Tools/Services.
-
Locate our service in the list and left click it.
-
You'll notice the service is NOT started.
-
Click "Start".
-
-
Notice that the service is now started and running.
-
-
Switch back to the Event Viewer and refresh the view.
-
You should now notice our new event source.
-
-
Opening our event source, there should be a single message noting the service start.
-
-
REMOVE
-
Switch back to the Services window.
-
Stop the service by clicking the "Stop" link after selecting the service.
-
-
Now open Add or Remove Programs via Start/Control Panel/Add or Remove Programs.
-
Locate our service application.
-
Select it and click "Remove".
-
Once the uninstall is complete, removal is done.
And that, dear reader, is how we write a Windows Service application using Visual Studio 2010.
Enjoy
C