Implement, Install and Control a Service
A Windows Service is a process without a user interface, that runs constantly in the background in its own session. This said, hit CTRL+ALT+DEL, select the Task Manager, then the Services pane, and hit the Services button. First ensure that you are using Windows, then that you have administrative rights. What you will see are the Windows Services. Friend with them, they are not malevolent.
Now that we know what is exactly a Windows Service, let’s try to create one. There are two ways to do so, the easy one with Visual Studio pregenerating all of the exciting code – and the cool way to write it by hand. You can choose any one of them, the result will be the same.
Unfortunately a service cannot be run by itself (as long as it isn’t a WCF service, but for this objective, it isn’t), so you cannot debug your services and test them with Visual Studio, which is definitely a bad thing.
Anything related to Windows Services lives in the System.ServiceProcess namespace, which lives in the shockingly named System.ServiceProcess.dll. And all services must inherit from the ServiceBase class, for very practical reasons. ServiceBase exposes a set of virtual voids, from which you will need to override at least two for a working service. These are namely OnStart and OnStop. But let’s see all of them in one table:
|OnStart||The method being called when a user starts the service, or when the computer runs it (when automatic startup is enabled). Optional string arguments can be processed here.|
|OnStop||The method called if your service stops for any reason.|
|OnPause||Occurs when a pause command is received through the Service Management Console.|
|OnContinue||Occurs when a continue command is received through the SMC.|
|OnShutdown||Occurs at system shut down.|
|OnPowerEvent||Occurs when the power status changes (a laptop hibernates itself). Takes a PowerBroadcastStatus enumeration.|
|OnSessionChange||Executes when a change event is received from a Terminal Server session.|
Note that in order to process these methods, you must set the appropriate properties of your service, which are: CanHandlePowerEvent, CanHandleSessionChangeEvent, CanPauseAndContinue, CanShutdown, CanStop. I think no further explanation is needed here.
Something beautiful for the exam: the SessionChangeReason enumeration. The values are self-explaining: ConsoleConnect, ConsoleDisconnect, RemoteConnect, RemoteDisconnect, SessionLock, SessionLogOff, SessionLogOn, SessionRemoteControl, SessionUnLock.
It’s worth mentioning that you must set the ServiceName property under all circumstances. This property must be unique for every service, because the operating system finds your service by this name. It is not the friendly name shown in the SMC.
ServiceBase is useful when you are creating your service. Now let’s move on and take a look at how to add install it!
The ServiceInstaller class installs a class that extends the ServiceBase class. The install utility calls this class during the installation of the service. You can add a ServiceInstaller class with Visual Studio, or you can do it by hand. The point is when you did so, you can set the following properties:
- StartType: can be Automatic, Disabled or Manual. Sets the start type of the service.
- Account: the owner of the service process. Can be:
|LocalService||Provides the best security, runs as a nonprivileged local user, presents anonymous credentials to a remote server.|
|NetworkService||Can authenticate to another computer on the network, but this isn’t required for anonymous connections.|
|LocalSystem||Avoid it. The service runs with unlimited privileges, and uses the computer’s credentials when authenticating on a remote server.|
|User||The service runs under the specified user (or ask for credentials at startup).|
- DisplayName: the friendly name to be shown at SMC.
- Description: the purpose of the service, shown at SMC.
- ServiceName: the name of the service to install. Must be valid, existing, etc.
You need to add a ServiceProcessInstaller class for each service application, and add a ServiceInstaller class for each service in the given service application.
If you are expecting the ServiceInstaller to install your service, mark it with a RunInstaller attribute, and set it to true.
Now you have two ways of deploying your service: using the InstallUtil.exe and specifying the assembly in which your installer class lives, or simply add a Setup Project to your solution, and set the primary output to the service project, and MSI takes care of the rest.
Good news, you can manage and monitor services programmatically. To do so, use the ServiceController class. ServiceController needs to know two things: the name of the computer, and the name of the service. There are three ways to add a ServiceController: in the Server Explorer pane, select Servers, the appropriate computer, Services, and then right click on the service you wish to work with, and select Add To Designer.
The second method is to drag it from the toolbox (from Components). Then set the computer name and the service name.
The third method is to write it from scratch. Create an instance of the ServiceController class. Then set the service name and computer name in the constructor, or by properties. Then you can work with it just like the ServiceBase-derived class.