Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / HPC / parallel-processing

General Windows Service: Debugged as Console Application and Managed with System Tray

4.90/5 (43 votes)
11 Mar 2014CPOL7 min read 49.5K   2.9K  
General solution for the Windows service: run as console for debugging, self-installing and -uninstalling, providing description, queuing and processing of messages, status observation and control with icon in system tray. The code may be reused for virtually any Windows service.

Introduction

.NET Windows service is one of the most popular types of the Windows projects. And yet Visual Studio offers an inconvenient template for it. The main problem with this template in my opinion is that generated code cannot run as console application for convenient debugging. But this is not the only problem. Dealing with Windows service, the developer normally needs to implement a more adequate thread model than the provided by the Visual Studio template. It would be also nice to manage the service and see its current status with icons and pop-up menu in the system tray. This article and code will address all these problems.

Background

As it was stated above, good practice of using Windows service implies collaboration of the service itself with its control from the system tray. Since windows service does not have visual aspect (and in fact even runs in different from normal applications desktop) another application should ensure proper indication of the service current status in system tray. In our sample this additional application is written in WPF. Normally this additional "tray-targeted" application is running in the same machine with the Windows service. Thus dual WCF with IPC (net.pipe) binding seems to be a natural choice for communication between the two processes where Windows service acts as a server.

Many developers (including me) particularly like when code intending to solve practical problems can be reused easily. For most of the practical cases the entire code provided in this article may be used almost as it is (changing text variables and names of modules only) with just few places to put specific Windows service functionality. All places in the SampleWinService project that may require changes are placed in appropriate regions entitled DIFFERS FOR EACH SERVICE.

User interface of the tray-target application provides appropriate icon indicating current status of the service and pop-up menu which in activated by mouse right click over the icon:

  • Service is not running

    Image 1

    Image 2


  • Service is running

    Image 3

    Image 4

Please note that icon indicating current service state is updated with certain delay after the service state has been changed.

Design

The Windows service SampleWinService possesses the following features:

  • Capable of running either as console application or as Windows service,

  • Being used as Windows service enables self-installing and self-uninstalling,

  • Act as server for "useful" clients and WPF tray-targeted application by hosting WCF dual service object,

  • Provide command-based working paradigm operating as following. Client application sends commands via WCF communication. The commands are queued by WCF service object to command queue. Commands are dequeued and processed by a dedicated working thread running in a loop. Result of the processing is sent to the calling useful client (if required), whereas current Windows service status is sent to the WPF tray-targeted application. Both result and status are sent as callbacks using WCF dual mechanism. Dual WCF is particularly useful in cases when number of useful clients in not very high and they reside within the same LAN with the service machine. Normally the tray-targeted application runs in the same machine with Windows service. So in this case dual WCF with IPC (net.pipe) binding is also a good choice for communication.

In our sample, external applications providing commands cause the service to perform useful work. In real life there can be also other sources of useful command, such as input from hardware, drivers, timers, etc.

Design of our SampleWinService is based on the following reasonable suppositions:

  • Tray-targeted GUI application runs in the same machine with the service,

  • Limited number of clients of the Windows service, and

  • No firewall between the service and all its clients.

The first supposition allows tray-targeted application to use asynchronous notification about changes in the service status provided by the System.Management.ManagementEventWatcher class. The second and the third suppositions justify usage of dual WCF service. Of course, the above suppositions are not mandatory and are made just for simplicity. We will briefly review other cases below, in the Discussion chapter of this article.

Block-diagram of the system is depicted below:

Image 5

Windows Service

Windows service contains WCF service object which accepts calls from useful clients and tray-target client sending commands to the service. The WCF part is implemented in ComminicationSvc project in the Libraries\ServiceLibs folder. Interface

ICommSvc
allows clients to send commands of type Cmd to the service. The interface is implemented by type
CommSvc
. The class
Cmd
contains command name and parameters, as well as information about client who sent the command. Interface ICallback constitutes contract for clients' callback. For client convenience the WCF service supports three endpoints for CommunicationSvc.ICommSvc contract with netNamedPipeBinding, netTcpBinding and wsDualHttpBinding bindings.

Since, according to the above suppositions, our Windows service does not have too many clients and the clients are available for back notification, the service can process clients' commands in a separate worker thread running in a loop. Project CommunicationSvc provides singleton the class CommandQueue<T> for synchronized command queue parameterized with the Cmd command type. The method CommSvc.Command() inqueues incoming commands for processing. Dequeueing and processing of the commands are performed in the main Windows service process SampleWinService. Unnamed method of type PeriodicProcessingDelegate in WorkerThread.StartThread() dequeues commands and processes them with static method CommandProcessor.Process(). This method is responsible for actual processing of commands. It is the only part of the service which varies according to actual task of the given Windows service. After processing methods SendStatusToAllClients() and SendReport() of class SampleWinSvc send status and result of processing to clients as asynchronous callbacks.

Clients

Both tray-targeted and useful clients use client part (proxy) of WCF. To share the same code between different types of clients, it is placed in a separate assembly ClientLib. In addition, tray-targeted client uses specific NotifyIconWpf assembly developed by Philipp Sumi ([1], www.hardcodet.net) providing infrastructure for tray icon and pop-up menu in WPF applications. Both tray-targeted and useful clients implement interface

ICommSvcCallback 
(corresponds to
ICallback 
interface on the server side) to receive notification calls from the service. Interestingly enough, in some cases the tray-targeted GUI application may be used even in stead of Windows service, e. g. when you need to run this application to capture a screenshot which is not possible for Windows service running in different desktop, or just for the sake of simplicity in for non-mission-critical tasks.

Code Sample

In our sample Windows service is presented with SimpleWinService project, and projects IconClient and TestClient represent icon-targeted and useful clients respectively.

Demo

To run demo we have to perform self-registration of the SimpleWinService Windows service. Run file SimpleWinService_Install.cmd (which starts SimpleWinService.exe with argument /install) for this purpose. Than start IconClient.exe and use tray icon and connected to it pop-up menu to control SimpleWinService Windows service and observe its status.

Discussion

Design described above is applicable to many practical cases of usage Windows services. In case of firewall between the service and its client in stead of dual WCF other approaches may be used, like for instance technique of "smart polling" (described e. g. in [2]) when sever holds client's repeatable polling calls on waitable object until either notification about the server event needs to be send to client or certain timeout elapsed. More sophisticated messages queuing and processing mechanism may be taken e. g. from [3].

Conclusions

This article presents solutions for Windows service general design by providing uniform technique for such widely desirable features as possibilities to run it as console application to facilitate debugging, self-installing and -uninstalling, providing description, queuing and processing of messages, as well as the service status observation and control with icon and pop-up menu placed in the system tray. The code accompanying this article may be reused almost as is (with just minor changes at few places marked in code by a specific regions) as a template for virtually any Windows service. I do hope that my fellows CodeProjecteers will find it useful when it comes to Windows service developing.

References

[1] Philipp Sumi. WPF NotifyIcon. CodeProject.
[2] Igor Ladnik. Push Messages in RESTful WCF Web Application with Comet Approach. CodeProject.
[3] Igor Ladnik. Tiny Framework for Parallel Computing. CodeProject.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)