We all know what a WindowsService
is - a long running executable that's designed to work without user
interaction. They can be configured to start when the system boots and
they can be run without any users logged into the system. This tutorial
is going to provide step-by-step instructions on how to build a Windows
Service using C# and .NET.
The first thing you're going to want to do is create a new Console
Application in Visual Studio. I like to start building services as
console applications so they can easily be tested and debugged before
converting them to services.
In order to build services, we depend on some .NET objects location in
the
System.ServiceProcess
and System.Configuration.Install
assemblies. Go ahead and add those references to your project.
When you created the project, Visual Studio should have created a file
called
Program.cs
, which looks something like this:using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyWindowsService
{
class Program
{
static void Main(string[] args)
{
}
}
}
The only thing we need to do in order to make this class into a service
is make
Program
extend
System.ServiceProcess.ServiceBase
.using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceProcess;
namespace MyWindowsService
{
class Program : ServiceBase
{
static void Main(string[] args)
{
}
}
}
By extending
ServiceBase
, we're given a bunch of service related
functions we can override. At a minimum, every service should override
OnStart
and OnStop
. These are where, as the names imply, your custom
logic should go when the service is started and stopped.class Program : ServiceBase
{
static void Main(string[] args)
{
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
//TODO: place your start code here
}
protected override void OnStop()
{
base.OnStop();
//TODO: clean up any variables and stop any threads
}
}
There are several other functions beyond start and stop like pause,
continue, and shutdown, but they're not needed for a basic service. For
all available functions, check out the ServiceBase memberlist
on MSDN.
Now we need to add some information about our service - like a name.
Let's add a constructor to
Program
and put it there.class Program : ServiceBase
{
static void Main(string[] args)
{
}
public Program()
{
this.ServiceName = "My Service";
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
//TODO: place your start code here
}
protected override void OnStop()
{
base.OnStop();
//TODO: clean up any variables and stop any threads
}
}
The constructor is where you'd also set lots of other information about
your service (if the default settings wouldn't work). These can include
things like which events it can handle, what operation it can do (pause,
stop, etc.), and what event log it should log information to
(application, system, etc.). For us, however, the default settings will
work just fine.
We're very close to having a finished service. All that left is to tell
Windows what service to run when your application it executed. Just like
normal applications, execution begins in the
Main
function. This is
where we'll create an instance of our service and tell it to run.class Program : ServiceBase
{
static void Main(string[] args)
{
ServiceBase.Run(new Program());
}
public Program()
{
this.ServiceName = "My Service";
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
//TODO: place your start code here
}
protected override void OnStop()
{
base.OnStop();
//TODO: clean up any variables and stop any threads
}
}
That's it! The service implementation is complete. We can't install it
yet though, because we haven't implemented an installer. To do that we
need to add another class to our project called
MyWindowsServiceInstaller
.using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyWindowsService
{
class MyWindowsServiceInstaller
{
}
}
When Visual Studio creates a class for you, it doesn't automatically
make it public. It's very important that this class be made public. When
you install a service, the installer will look through your assembly for
public classes with a specific attribute. If it's not public, it won't
find it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyWindowsService
{
public class MyWindowsServiceInstaller
{
}
}
This class needs to extend
System.Configuration.Install.Installer
and be given a RunInstaller attribute. This is the attribute that the
service installer looks for when installing your service.using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration.Install;
using System.ComponentModel;
namespace MyWindowsService
{
[RunInstaller(true)]
public class MyWindowsServiceInstaller : Installer
{
}
}
Now we need to configure how we want our service installed. We'll do
this in the constructor for the class we just created.
[RunInstaller(true)]
public class MyWindowsServiceInstaller : Installer
{
public MyWindowsServiceInstaller()
{
var processInstaller = new ServiceProcessInstaller();
var serviceInstaller = new ServiceInstaller();
//set the privileges
processInstaller.Account = ServiceAccount.LocalSystem;
serviceInstaller.DisplayName = "My Service";
serviceInstaller.StartType = ServiceStartMode.Manual;
//must be the same as what was set in Program's constructor
serviceInstaller.ServiceName = "My Service";
this.Installers.Add(processInstaller);
this.Installers.Add(serviceInstaller);
}
}
This is pretty much the bare minimum when it comes to service options.
We have to create a
ServiceProcessInstaller
and a
ServiceInstaller
.
These two classes are responsible for installing the service. The
ServiceProcessInstaller
installs information common to all services,
and the ServiceInstaller
installs information for this specific
service.
The
Account
property sets which privileges you'd like the service to
run under. The default is User
, but then we'd have to specify a
username and a password to determine the account. I chose LocalSystem
,
which gives the service a lot (probably too much) access to the local
computer.
Services are identified by name, so you have to ensure
serviceInstaller.ServiceName
is exactly the same as what you set in
the constructor of Program
. The rest of the options are pretty
obvious. All that's left is to add our two installers to the
Installers
collection.
We're done! All that's left to do now is install the service.
Installing The Service
Services are installed using a tool from Microsoft called
installutil.exe.
This tool is free and is probably already on your computer. I doubt it's
in your system path, so you might want to do a quick search for it and
add it to your environment variables before continuing.
All you have to do to install your service is open a command prompt, cd
to your Release directory, and type:
installutil MyWindowsService.exe
Your service is now installed and ready to go. If you bring up your
services manager, you should see one labeled "My Service". Of course, if
you start it, nothing will happen since we didn't actually put any code
in the OnStart function.
If you want to uninstall the service, you can do so with the same
utility but with the "-u" flag.
installutil -u MyWindowsService.exe
There's a lot of power that we haven't even touched in Windows Services,
but this tutorial should hopefully give you a starting point on which
you can expand and build some much more complex solutions. All of the
example code has been attached as a Visual Studio 2008 solution.
Source Files:
Comments
Post a Comment