A Windows Service without a template
Written by Harry Fairhead   
Friday, 14 August 2009
Article Index
A Windows Service without a template
A simple service
Using Timers
Event log service
Other logs

Eventer

The Event Log is the place that a lot of important system components and applications send their status, warning and error messages. The problem is that most users either don’t know about it or don’t bother to look at it.

There is a utility, Control Panel/ Administrative Tools/ Event Viewer, that you can use to check that your machine is working properly but it would be better if really important messages were brought more forcibly to your attention – this is what Eventer is designed to do.

It is a service that monitors the event log and emails new events as they occur.

To create Eventer all you have to do is create a new service called Eventer following the steps given earlier.

Start a new empty project called Eventer, add a code file called Eventer and add references to:

System, System.Configuration and System.ServiceProcess.

and add to the start of the program:

using System;
using System.ServiceProcess;
using System.Configuration.Install;
using System.ComponentModel;
using System.Diagnostics;
using System.Net.Mail;
using System.Net;

The Eventer service starts in the usual way:

public class Eventer : ServiceBase
{
public Eventer()
{
this.ServiceName = "Eventer";
this.CanStop = true;
this.CanPauseAndContinue = false;
this.AutoLog = true;
}

The AutoLog property being set to true means that the service automatically writes start and stop events into the event log.

The OnStart and OnStop methods are very simple because there is an EntryWrittenEvent which can be used to activate the service without the need to use a timer. All we have to do to make the service respond to the event is to add an event handler in the OnStart method and turn the events on:

protected override void OnStart(
string[] args)
{
this.EventLog.EntryWritten +=
new EntryWrittenEventHandler(
MyOnEntryWritten);
this.EventLog.EnableRaisingEvents
= true;
}

Notice that in this case we can’t use the form’s designer to connect an event to an event handler – it has to be done using code. This isn’t difficult as all you need to do is add a suitable delegate, EntryWrittenEventHandler, to the event using the += operator.

Of course we still have to write the code in the MyOnEntryWritten event handler. In the OnStop method we need to remove the event handler and this is just as easy using the -= operator on the event:

protected override void OnStop()
{
this.EventLog.EnableRaisingEvents
= false;
this.EventLog.EntryWritten -=
new EntryWrittenEventHandler(
MyOnEntryWritten);
}

 

This is all we need to get the service started and stopped and the Main method only has to create an instance of the service to complete the code:

public static void Main()
{
ServiceBase.Run(new Eventer());
}

 

The installer for the service is similar to previous installers but this time the ServiceStartMode is set to Automatic which starts the service as soon as the machine is started:

[RunInstaller(true)]
public class EventerInstaller
: Installer
{
private ServiceProcessInstaller
processInstaller;
private ServiceInstaller
serviceInstaller;
public EventerInstaller()
{
processInstaller =
new ServiceProcessInstaller();
serviceInstaller =
new ServiceInstaller();
processInstaller.Account =
ServiceAccount.LocalSystem;
serviceInstaller.StartType =
ServiceStartMode.Automatic;
serviceInstaller.ServiceName
= "Eventer";
Installers.Add(serviceInstaller);
Installers.Add(processInstaller);
}
}

The only method we still need to write is the event handler which is called every time a new event is written to the Application event log. When you create a service object it has an EventLog property which is connected to the local machine’s Application event log. You can create other EventLog objects connected to other event logs – Security, System and so on if you want to scan for errors in specific categories - but for the moment working with the Application log provides an easy example. However, it is worth knowing that you can’t change the EventLog property to work with any other event log, you have to create new EventLog objects.

The information about the entry that has just been written and hence caused the EntryWritten event is contained in the second parameter passed to the event handler. We could test the event type and only email information about it if it was serious enough – at least a warning or an error.Again for simplicity is it easier to initially email all events in the log including low priority information events.

Our first task is to assemble the email to be sent. Version 3 (and later) of the .NET framework makes this very easy with the introduction of a range of SMTP classes.

First we create a MailMessage:

 

public void MyOnEntryWritten(
Object source,
EntryWrittenEventArgs e)
{
MailMessage mail=
new MailMessage("from","to");

where you replace from and to by appropriate email addresses. You can also use the many properties provided by MailMessage to set, subject, from, to, and even add attachments.

In this particular case we simply need to set the subject and build up the text to be used as the body of the email:

mail.Subject = "Event Notification";
mail.Body=e.Entry.Source
+Environment.NewLine+e.Entry.Message
+Environment.NewLine
+e.Entry.TimeGenerated.
ToLongDateString()
+" "+ e.Entry.TimeGenerated.
ToLongTimeString()
+Environment.NewLine
+ e.Entry.MachineName
+ Environment.NewLine
+ e.Entry.EntryType;

The instructions that create the body of the email may look complicated but they simply build up the text using properties supplied by e.Entry such as date, time, message etc. You can include or leave out other details of the event to suit your requirements.

Now that we have the email ready to send we can use the SmtpClient to create a connection to an SMTP server.

The documentation gives the impression that SmtpClient is to be used with an SMTP server provided by a local IIS virtual SMTP server but in fact it is completely general and you can send email using any mail server that you have a valid account on.

First we create an SmtpClient:

SmtpClient mailbox=
new SmtpClient("smtp server");

You can replace smtp server with either the IP address or URL of the mail server you plan to use. Some mail servers require you to log on before you can use them to send an email. If this is the case you will need to set the Credentials property:

mailbox.Credentials =
new NetworkCredential(
"user", "password");

where you replace user and password by a valid username and password.

Finally we can send the mail message using the SMTP server:

 mailbox.Send(mail);
}

This completes the event handler and now all you need to do is install the service using InstallUtil.

Once the service is started it will send one email for each new event in the Application log.

Of course there are a few things that need to be done to make the service robust but this is a reasonable first attempt. In particular you need to add some code to handle SMTP errors just in case the mail server isn’t correctly configured or offline.

<ASIN:047138576X>

<ASIN:0735623740>

<ASIN:0735621632>



Last Updated ( Friday, 14 August 2009 )