creating a windows service

23
Creating a Windows Service Windows services are background processes that usually have no direct interaction with the user interface. This article explains how to create a windows service with an example that monitors the file system for changes using a FileSystemWatcher object. >> Download Source Code Windows Services Windows services were introduced in Windows NT under the name, "NT Services". A service is simply a long-running executable program that runs in the background in its own Windows session. Services are therefore ideal for monitoring applications and for reacting to events . For example, in this article we will create a service that reacts to the creation, modification and deletion of files using the FileSystemWatcher class . Services can also be used for scheduled processes using timer events, though consideration should be given to using the standard scheduling tools provided by Windows in these cases. Services do not usually include any graphical user interface elements. Although it is possible to display dialog boxes and other windows from a correctly configured service, this is usually inappropriate. One of the primary considerations is that services do not require an interactive user to be logged on to Windows. In fact, if a service is set to start automatically, it may be executing before the log on screen is displayed. For these reasons, direct user input is usually not included in a service and output is generally logged to the event log , a file or a database. Service Accounts As a service does not require that an interactive user be logged on, the service itself logs on to Windows separately. This allows a service to use a different account to that of any interactive user of the computer, potentially with different privileges. The user credentials for the service are first supplied when it is installed. The account may be any of the following:

Upload: robson-mamede

Post on 25-Nov-2015

16 views

Category:

Documents


6 download

TRANSCRIPT

Creating a Windows Service

Creating a Windows Service

Windows services are background processes that usually have no direct interaction with the user interface. This article explains how to create a windows service with an example that monitors the file system for changes using a FileSystemWatcher object.>> Download Source CodeWindows Services

Windows services were introduced in Windows NT under the name, "NT Services". A service is simply a long-running executable program that runs in the background in its own Windows session. Services are therefore ideal for monitoring applications and for reacting to events. For example, in this article we will create a service that reacts to the creation, modification and deletion of files using the FileSystemWatcher class. Services can also be used for scheduled processes using timer events, though consideration should be given to using the standard scheduling tools provided by Windows in these cases.

Services do not usually include any graphical user interface elements. Although it is possible to display dialog boxes and other windows from a correctly configured service, this is usually inappropriate. One of the primary considerations is that services do not require an interactive user to be logged on to Windows. In fact, if a service is set to start automatically, it may be executing before the log on screen is displayed. For these reasons, direct user input is usually not included in a service and output is generally logged to the event log, a file or a database.

Service Accounts

As a service does not require that an interactive user be logged on, the service itself logs on to Windows separately. This allows a service to use a different account to that of any interactive user of the computer, potentially with different privileges. The user credentials for the service are first supplied when it is installed. The account may be any of the following:

Standard User. Any user name and password may be provided to assign that user's permissions to the service. This option is usually used during development rather than for production systems. One problem is that if the user changes their password, the service will need to be reconfigured to enable it to log on.

Local Service. The built-in local service account is specific to the local computer and has reduced privileges. This account presents anonymous credentials to any remote computer, restricting its scope for using network resources. This account is ideal for services that require limited or no access to network resources.

Network Service. The network service account is built into Windows. It provides reduced privileges to the local computer. The network service account is does provide access to remote computers. This account is ideal for services that require substantial access to network resources.

Local System. This built-in account provides full access to the local computer's resources, including control of the directory service if installed on a domain controller. This account should be used with care as, if used maliciously, it has the capability of accessing the entire domain.

Microsoft Management Console

Windows services are installed differently than normal applications. Whereas a standard executable program may have a shortcut in the Start menu or on the desktop, a service is controlled using the Services snap-in for the Microsoft Management Console (MMC). This is accessed using the Services option from the Administrative Tools section of the Control Panel.

In the Services window, the full list of installed services is displayed. These can be started and stopped or paused and resumed using the tools of the snap-in. By modifying a service's properties, it can be made to start automatically when the operating system is booted, manually by a user, or it can be disabled altogether. The service's user account and password may also be configured using this tool.

A full description of the Services snap-in is beyond the scope of this article. However, the basics of starting and stopping a service will be used later in the article once the example service is installed.

Creating a Service

In this section of this article we will create a Windows service using C# and Microsoft Visual Studio. The edition of Visual Studio is important, as we will be using the Windows Service template project. In some editions, such as Visual C# Express, this template is not available. This does not prevent you from creating a service in Visual C# Express or another, non-Microsoft development environment. However, the process is more complicated.

The service that we will create will perform a very simple function. On starting, a FileSystemWatcher object will be created and set to monitor the contents of a folder. Whenever a change is detected due to the creation, deletion, modification or renaming of a file in the folder, the update will be logged in the event log. In a real-world application, the service would probably be modified to perform some activity using the files. In this case, adding such functionality would only complicate the examples.

Creating the Project

To begin, we need to create a project in Visual Studio using the Windows Service template. Start Visual Studio and specify that you want to create a new project. You should see the option and icon for creating a Windows Service project. Select this option and name the project "FileMonitorService".

Once the new project is created, you will see that it contains a class file named "Service1". This is the class that contains the basic functionality of the service. If you double-click the file you will see that, rather than viewing the code immediately, a design window is displayed. In a similar manner to when creating Windows forms applications or components, you can drag components from the toolbox into this designer and use them with your service.

To view the code in the Service1 class, you can click the "click here to switch to code view" link on the designer's surface or right-click the file in the Solution Explorer and choose "View Code". You will see that the class file contains some methods. The actual code will vary according to the version of Visual Studio that you are using. However, it will include the following members:

Constructor. A constructor will be defined and will make a call to InitializeComponent. This is required to enable the components that you add to the service using the designer.

OnStart. This method is called when the service is started, either manually via the MMC or automatically when the operating system is loaded.

OnStop. This method is called when the service is stopped.

You should also note that the Service1 class inherits from ServiceBase. This base class contains the methods required to correctly operate a Windows service, including OnStart and OnStop, which are overridden in the code.

Service1 is not a good name for the class. Rename the class file from "Service1.cs" to "Monitor.cs" and change the class definition to match the following. NB: If the current definition includes the "partial" keyword, leave this in place and just change the name of the class.public class Monitor : ServiceBase

Depending upon the version of Visual Studio that you are using, the base class may have been fully qualified before we changed it. To ensure that the service will still compile, add the following using directive to the top of the code if it is not already present:

using System.ServiceProcess;

The service will still not be able to be compiled at this point, as the name of the constructor must match the name of the class. Modify the declaration of the constructor as follows, then check that the code will compile.

public Monitor()

NB: At this point you may find that the code does not compile because there is a reference to the Service1 class in the Main method. If this is the case, simply change the name from "Service1" to "Monitor" and try compiling again.ServicesToRun = new ServiceBase[] { new Monitor() };

Initialising the Service

Any initialisation that is required would usually be added in the constructor, following the call to InitializeComponent. In the case of our simple example service, the only initialisation required is to ensure that an event source exists so that we can log events successfully. However, as the service may execute under a user account with limited privileges, it may not be possible to create the event source within the service. Additionally, on some operating systems it is not possible to create an event source unless the program is running as an administrator.

A typical solution to this problem is to create a separate program to create the event source and run this as an administrator before the service is used. This is explained in the article, "Logging Messages in Event Logs". If you do not wish to read that article now, simply create a new console application, add the following code to the Main method and run the program once.

string eventSource = "File Monitor Service";

System.Diagnostics.EventLog.CreateEventSource(eventSource, "Application");

NB: If you are using Microsoft Vista or a more recent operating system, you will need to compile the program and run it as an administrator.Logging Events

Each time an event happens within the service, we will log a message in the event log. This logging will occur when the service is started, stopped, paused or resumed and when the FileSystemWatcher object captures a file change event. To simplify the code, we will create a single method that logs all events. First, ensure that the following using directive appears at the top of the code in Monitor.cs:

using System.Diagnostics;

Once the using directive is present, add the following method to the Monitor class. This method accepts a message as a string and adds it to the event log using the event source created earlier.

void LogEvent(string message)

{

string eventSource = "File Monitor Service";

EventLog.WriteEntry(eventSource, message);

}

Adding the OnStart Method

When a service is started, the OnStart method is called. This is where we will initialise our FileSystemWatcher object and set it to monitor a folder for changes. The code for this is quite simple and has already been explained in the article, "Detecting File Changes with FileSystemWatcher", so I will not describe it in detail again.

As the FileSystemWatcher object must exist beyond the scope of the OnStart method, we will begin by declaring it as a class-level variable. Add the following declaration within the class but outside of any method definition:

private FileSystemWatcher _watcher;

You may also need to add an extra using directive to the code to provide access to the FileSystemWatcher class:

using System.IO;

We can now initialise the FileSystemWatcher within the OnStart method. Much of this code could have been included in the constructor. However, I have included it in OnStart so that we can dispose of the object when stopping the service and recreate it each time the service is restarted. On completion of this step, we will also log an event.

Modify the OnStart method as follows to create the object, attach its events and begin monitoring.

protected override void OnStart(string[] args)

{

_watcher = new FileSystemWatcher();

_watcher.Path = @"c:\watched";

_watcher.Changed += new FileSystemEventHandler(LogFileSystemChanges);

_watcher.Created += new FileSystemEventHandler(LogFileSystemChanges);

_watcher.Deleted += new FileSystemEventHandler(LogFileSystemChanges);

_watcher.Renamed += new RenamedEventHandler(LogFileSystemRenaming);

_watcher.Error += new ErrorEventHandler(LogBufferError);

_watcher.EnableRaisingEvents = true;

LogEvent("Monitoring Started");

}

NB: Note that the Path property of the _watcher object is set to "c:\watched". This is the folder that will be monitored. If you wish to use this folder, create it now. If not, change the Path property to that of an existing folder to monitor for changes.Adding the Logging Methods

The OnStart method creates a new FileSystemWatcher object and connects five of its events to three methods. These methods will use the information from the event arguments passed to them to create event log entries for file changes or log buffer overflow errors. To define these methods, add the following to the class:

void LogFileSystemChanges(object sender, FileSystemEventArgs e)

{

string log = string.Format("{0} | {1}", e.FullPath, e.ChangeType);

LogEvent(log);

}

void LogFileSystemRenaming(object sender, RenamedEventArgs e)

{

string log = string.Format("{0} | Renamed from {1}", e.FullPath, e.OldName);

LogEvent(log);

}

void LogBufferError(object sender, ErrorEventArgs e)

{

LogEvent("Buffer limit exceeded");

}

Adding the OnStop Method

When a service is stopped, the OnStop method is called. In the sample project, we will use this method to disable and dispose of the FileSystemWatcher object, freeing the resources it uses. We will also send a message to the event log. To do so, change the OnStop method as follows:

protected override void OnStop()

{

_watcher.EnableRaisingEvents = false;

_watcher.Dispose();

LogEvent("Monitoring Stopped");

}

Adding OnPause and OnContinue Methods

Often a Windows Service has the ability to be paused and resumed. This is useful if the start-up process for a service is slow or uses many resources. Although this is not true for our example, we will add pause and continue functionality for demonstration purposes.

When a new service is created, it does not support pausing and resuming by default. These options must be configured within the project before compiling. The simplest method to achieve this is to return to the designer for the service and set its properties.

Double-click the Monitor.cs file in the Solution Explorer to view the designer surface. If you cannot see its properties, right-click the grey background of the designer and choose Properties from the menu that appears. You should see a set of properties that determine which actions the service can use. To enable pausing and resuming, set the value of the CanPauseAndContinue property to True.

You should also see a property named, "AutoLog". When set to True, this property indicates that standard messages should be logged in response to the service events, such as starting and stopping. As we are logging our own messages for these activities, set the AutoLog property value to False. We can also set a friendlier name for the service by changing the ServiceName property to "File Monitor".

We can now add the code to react to pausing and continuing execution of the service. We do this by overriding methods from the ServiceBase class. Add the following to methods to the Monitor class:

protected override void OnPause()

{

_watcher.EnableRaisingEvents = false;

LogEvent("Monitoring Paused");

}

protected override void OnContinue()

{

_watcher.EnableRaisingEvents = true;

LogEvent("Monitoring Resumed");

}

Other Events

Windows services can react to two additional events, each with its own enabling property and overridable method. The OnShutdown method is called when the computer is being shut down completely. The OnPowerEvent method captures changes to the computer's power status, such as the machine being suspended. For the example service we will not implement these methods.

Adding an Installer

The basic code for the Windows service is now complete. However, at the moment it will not be possible to install the service so that it can be configured using the Microsoft Management Console. In order to permit this, we need to add installer components to the service. This can be achieved simply using Visual Studio.

Double-click the Monitor.cs file to redisplay the designer for the service. Right-click the grey background and select "Add Installer..." from the context-sensitive menu that appears. This will add two components to the designer; a ServiceInstaller and a ServiceProcessInstaller.

The two components allow the configuration of the service to be modified. We will start by changing the service process installer. Click the component named "serviceProcessInstaller1" to select it and view its properties. The important property is Account. This allows you to define the default account that will be used by the service when it is running. This can be a user account or a system account. If a user account is selected, a password will be required during installation. In this case we want the service to run with limited privileges so select "LocalService" from the drop-down list.

The service installer component can be used to set general information relating to the service. This information is registered on installation and appears in the Services window of the MMC.

Select the serviceInstaller1 component. Change the DisplayName property to "File Monitor Demonstration Service".

Installing the Service

With the code complete and the installer added, we can now install the service. First, compile the service. This will generate the executable file that will be installed.

The service will access the watched folder and the executable files of the service itself using the user account specified earlier. To ensure that this will be possible, check the security permissions of this folder and the service's files to ensure that they can be read by the local service account.

Services are installed using a command-line program named "InstallUtil". This utility is installed as a part of the .NET framework. The easiest way to obtain access to it is using the Visual Studio command prompt tool. This is a special version of the command prompt utility that has predefined paths configured to simplify using tools such as InstallUtil.

Open a new Visual Studio command prompt by selecting the following Start Menu options. Start, All Programs, Visual Studio, Visual Studio Tools, Visual Studio Command Prompt. NB: If you have the option, right-click the icon and run the program as an administrator. If you do not have this option, you must be an administrator to successfully complete the install.Within the command prompt window, change the current folder to that of the compiled executable for the service. You can now install the service by executing the following command:

installutil FileMonitorService.exe

If the process is successful, open the Services utility from the Administrative Tools section of the Control Panel. The list of services should now include a new item named "File Monitor Demonstration Service". This is the descriptive name we specified earlier.

Starting the Service

You can now test the service. Using the Services window, try starting the service. You should find that a new event is logged and can be viewed using the Event Viewer. Try creating, modifying, renaming and deleting files to see further events logged. You can also pause the service to cease logging events temporarily, then resume to continue logging.

Uninstalling the Service

Once you have finished with the service, you will probably want to uninstall it. First, ensure the service is stopped. You can then remove it from the Services window by executing the following command at the Visual Studio command prompt:

installutil -u FileMonitorService.exe

Writing Windows Services in C#

starkos | 25 Aug 2005

What follows is a skeleton Windows service application written in C#, which you can use as a framework for developing your own services. It is based on Writing a Useful Windows Service in .NET in Five Minutes by Dave Fetterman, with a few changes to make it simpler, and to bring it up to date.

To start, here is the service class.

using System;using System.ServiceProcess;using System.Threading;

public class CronService : ServiceBase

{ private CronJob job; private Timer stateTimer; private TimerCallback timerDelegate;

public CronService() { this.ServiceName = "Cron"; this.CanStop = true; this.CanPauseAndContinue = false; this.AutoLog = true; }

protected override void OnStart(string [] args) { job = new CronJob(); timerDelegate = new TimerCallback(job.DoSomething); stateTimer = new Timer(timerDelegate, null, 1000, 1000); }

protected override void OnStop() { stateTimer.Dispose(); }

public static void Main() { System.ServiceProcess.ServiceBase.Run(new CronService()); }}This is the installer class. You will need to add a reference to System.Configuration.Install.dll.

using System.ComponentModel;using System.Configuration.Install;using System.ServiceProcess;

[RunInstaller(true)]public class CronInstaller : Installer

{ private ServiceProcessInstaller processInstaller; private ServiceInstaller serviceInstaller; public CronInstaller() { processInstaller = new ServiceProcessInstaller(); serviceInstaller = new ServiceInstaller(); processInstaller.Account = ServiceAccount.LocalSystem; serviceInstaller.StartType = ServiceStartMode.Manual; serviceInstaller.ServiceName = "Cron"; Installers.Add(serviceInstaller); Installers.Add(processInstaller); }

}The new service must be installed before it can be run. Open a .NET command prompt and do this:

C:\> InstallUtil /LogToConsole=true cron.exe # flag is optional but handy

C:\> net start cron

C:\> net stop cron # to stop the service when finished

C:\> InstallUtil /u cron.exe # to uninstall

That's it! Thanks again to Dave Fetterman for providing the original example.

Timer Objects in Windows Services with C#.NET

(Page 1 of 5 )

Timer events can be very useful when you need to run a routine on a regular basis. In .NET, creating Windows services with the timer object is very easy to do. In this article we are going to create a timer which writes text to a file on regular intervals, and well employ a Windows Service to control the timer.

Timer Object ConceptFrom the timer object (in the System.Timers namespace) we use the following properties and events:

Elapsed: Everything in the timer evolves around the Elapsed event, which is the event that is raised every interval. You create code to be executed and call that code in the Elapsed event.

Interval: Used to set the time between raising the Elapsed event.

AutoReset: Ensures that the timer will be reset after every Elapse event.Therefore, if you would only like to execute the Elapse event once, you set the AutoReset property to false. When you omit the AutoReset property, it is assumed to be true.

Enabled: Used to tell the timer to start or stop.

Windows Service ConceptA Windows Service has very defined start and stop events. Starting and stopping timers using these events is very organized and is run as a background process. If you define the Windows Service to start automatically, you need not worry about starting the timer again; this background process will keep on running until you stop the service and disable it. Since this is a background process, there will not be a user interface to dialog with the user. In case of exceptions, messages would be written to the Windows Event Log.

Every Windows Service must have a Main method where you issue a Run command, which loads the service into the Services Control Manager. However, if you use

.NET, all this code will be generated automatically.Visual StudioTimer Objects in Windows Services with C#.NET - Setting up the Project

(Page 2 of 5 )

1. Create a C# Windows Service project and name it TimerSrv.

The project will come with a class, Service1.cs. Double-click Service1.cs in the project explorer to reveal the properties. Name the service TimerSrv and in the ServiceName field also fill in TimerSrv.

2. Next we are going to add an installer to the project. Click on the hyperlink Add Installer. A design screen will be added to the project with 2 controls: serviceProcessInstaller1 and ServiceInstaller1.

3. Click the serviceProcessInstaller1 control and, in the properties dialog, change the account to LocalSystem.

4. In the serviceInstaller control, change the start type to Automatic, and give it a nice display name, like Timer Service.

Timer Objects in Windows Services with C#.NET - Adding Code

(Page 3 of 5 )

1. Switch to the code view of the Service1.cs file.

Note: we renamed the service to TimerSrv, so we need to change the Run command in the Main method of this class.Find the following line:ServicesToRun = new System.ServiceProcess.ServiceBase[]{ new Service1() };Now, change this to the following:

ServicesToRun = new System.ServiceProcess.ServiceBase[]{ new TimerSrv() };2. In the top of the file add use statements:

Use System.IO; // we need this to write to the file use System.Timers; //we need this to create the timer.3. Somewhere in the class, add a new private void AddToFile() method. We will use this to write text to a file.

private void AddToFile(string contents){ //set up a filestream FileStream fs = new FileStream(@c:\timerserv.txt, FileMode.OpenOrCreate, FileAccess.Write); //set up a streamwriter for adding text StreamWriter sw = new StreamWriter(fs); //find the end of the underlying filestream sw.BaseStream.Seek(0, SeekOrigin.End); //add the text sw.WriteLine(contents); //add the text to the underlying filestream sw.Flush(); //close the writer sw.Close();}Now we can start coding the events.

Timer Objects in Windows Services with C#.NET - Coding the Windows Service Start and Stop Event Handlers

(Page 4 of 5 )

In the Service1.cs file we only need to write code for the OnStart and OnStop events. In the OnStart() void method, add the following line of code:

AddToFile(Starting Service);Now, in the OnStop event add the following line:

AddToFile(Stopping Service);This is all we need to do to have a working Windows Service. Next well add the timer to the service.

Creating the TimerJust under the class definition in the Service1.cs file, add the following global variables:

//Initialize the timerTimer timer = new Timer();The idea behind the timer is that it sleeps for a specified period (defined by the interval method), and then executes the code specified with the elapsed event. We need to define a method that will be executed when the Elapsed event occurs, and we do this with the following code, which adds a line of text to the file:

Private void OnElapsedTime(object source, ElapsedEventArgs e){ AddToFile( Another entry);}Now we can setup the timer.

In the OnStart method we add code to reflect what to do when the elapsed event is raised. In this case, we need to invoke the OnElapsedTime method we defined above, set the interval (in milliseconds) the project needs to sleep, and enable the timer so it raises the Elapsed event.

The complete OnStart method looks like this:

protected override void OnStart(string[] args)

{ //add line to the file AddToFile(starting service);//ad 1: handle Elapsed event timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);//ad 2: set interval to 1 minute (= 60,000 milliseconds)timer.Interval = 60000;//ad 3: enabling the timertimer.Enabled = true;}The OnStop event also needs to be modified. A mere timer.Enabled = false suffices. The complete OnStop method looks like this:

protected override void OnStop(){ timer.Enabled = false; AddToFile(stopping service);}Thats all the coding we need to do!

Timer Objects in Windows Services with C#.NET - Building and Installing the Service

Build the executable: Build->Build SolutionIn order to install the service we need to use theinstallutil console command, which comes with the .NET Framework.

Open a command line window by going to Start -> Programs -> Microsoft

.Net -> Visual Studio.Net Tools -> Visual Studio.Net Command Prompt, and change to the directory where the executable is located. Enter the following command:Visual Studioinstallutil TimerServ.exe// Whatever you defined the executable // name to be.

Now the service is installed. To start and stop the service, go to Control Panel -> Administrative Tools -> Services. Right click the service and select Start.

Now the service is started, and you will be able to see entries in the log file we defined in the code.

ConclusionCreating a timer, using a Windows Service, with Visual Studio.Net is not such a difficult task. This article showed the entire process of creating a timer object and using a Windows Service as the control vehicle.