Thursday, February 5, 2009

Wrote a Windows Service

Wrote my first windows service today. Was not hard at all, I mostly followed the guide

Simple Windows Service Sample

However, the way the service in the sample is logging events was not suitable for me. I needed to log the events into the Application log of the Event Viewer. I also needed to catch exceptions and log them as errors in the Application log. So I used the powers of Enterprise Library event logging and exception handling. Firstly, I added references to EnterpriseLibrary and the corresponding 'usings' to the windows service


using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using Microsoft.Practices.EnterpriseLibrary.Logging;

Then, I added the loggingConfiguration and exceptionHandling sections to the appConfig file, that looked like this:


<configSections>
<section name="loggingConfiguration"
type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings,
Microsoft.Practices.EnterpriseLibrary.Logging, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=null" />
<section name="exceptionHandling" type=
"Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.
ExceptionHandlingSettings,
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
</configSections>

...

<loggingConfiguration name="Logging Application Block" tracingEnabled="true"
defaultCategory="" logWarningsWhenNoCategoriesMatch="true">
<listeners>
<add source=" " formatter="Text Formatter" log="Application"
machineName="" listenerDataType=
"Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.
FormattedEventLogTraceListenerData,
Microsoft.Practices.EnterpriseLibrary.Logging, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=null"
traceOutputOptions="None" type="Microsoft.Practices.EnterpriseLibrary.Logging.
TraceListeners.FormattedEventLogTraceListener,
Microsoft.Practices.EnterpriseLibrary.Logging, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name="MyService EventLog TraceListener" />
</listeners>
<formatters>
<add template="Timestamp: {timestamp} Message: {message} Category: {category} "
type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter,
Microsoft.Practices.EnterpriseLibrary.Logging, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=null" name="Text Formatter" />
</formatters>
<categorySources>
<add switchValue="All" name="MyService">
<listeners>
<add name="MyService EventLog TraceListener" />
</listeners>
</add>
</categorySources>
<specialSources>
<allEvents switchValue="All" name="All Events" />
<notProcessed switchValue="All" name="Unprocessed Category" />
<errors switchValue="All" name="Logging Errors & Warnings">
<listeners>
<add name="MyService EventLog TraceListener" />
</listeners>
</errors>
</specialSources>
</loggingConfiguration>

<exceptionHandling>
<exceptionPolicies>
<add name="PagingPolicy">
<exceptionTypes>
<add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
postHandlingAction="None" name="Exception">
<exceptionHandlers>
<add logCategory="MyService" eventId="100" severity="Error"
title="MyService Exception Handling" formatterType=
"Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter,
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=null" priority="0" type=
"Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler,
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging,
Version=2.0.0.0, Culture=neutral,
PublicKeyToken=null"
name="MyService Logging Handler" />
</exceptionHandlers>
</add>
</exceptionTypes>
</add>
</exceptionPolicies>
</exceptionHandling>

I'll be honest, I would not be able to explain every single line in this XML snippet. I just know that it works that way, and when I try removing some parts of it which seem to be unnecessary to me, the whole application usually starts failing.

Next, I put the following into the OnStart method of the service:


try
{
Logger.Write("MyService Process Started: " + getNow(), "MyService");
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Interval = 10000;
timer.Enabled = true;
}
catch (Exception ex)
{
ExceptionPolicy.HandleException(ex, "MyService");
errorCount++;
}

and into the OnStop method


Logger.Write("MyService Process Stopped: " + getNow(), "MyService");
timer.Enabled = false;

and into the timer_Elapsed method


Logger.Write("running MyService process at " + getNow(), "MyService");
RunMainFunction();

(getNow() simply returns DateTime stamp in the required format)

and I started getting events written into the Application log.

Actually, logging events into the event log seems to be faster and easier than trying to debug the service. At least with my little service, where the whole cycle of stopping service -> uninstallation -> building a service + installation package -> installation -> starting a new version of a service can be done in under one minute.

by . Also posted on my website

No comments: