Windows Services in C#: Pulling in the Event Log for your Windows Service (part 8)

Technically this falls in line closer with the EventLog series I did in January. (For more info see my series on event logging, it started on January 16 of this year and ran to the 19th, http://shrinkster.com/p6d). However, in most cases the Event Log is tied in closely with Windows Services since it’s through the event log that services do most of their communication with the outside world. As such it can be important to read in your events back into your control app.

To read the log we’ll use two different methods, just to show multiple techniques. To start, let’s add a text box to the TLManager, under the buttons. I named mine txtEventLog. Next, in the component area of the toolbox find the EventLog component and drop it on the form. Like the timer, it goes in the tray area under the form. I named mine TimerEventLog.

In the properties for the TimeEventLog, there’s a few properties we must set. First, set the Log property to “ArcaneTimeLogger” and the Source to “ArcaneTimeLoggerService”, so it will know to read our log.

Next set EnableRaisingEvents to true. This will allow the EventLog component to raise an event whenever something gets written to our log. Since we set this to true, we must indicate what method is responsible for the event. Click on the Event button (the lightening bolt) in the properties window to switch to events view, then double click the EventWritten to generate a default named event. It will generate TimeEventLog_EntryWritten.

Now switch to code view, and add this code to the event:

    private void TimeEventLog_EntryWritten(object sender, System.Diagnostics.EntryWrittenEventArgs e)

    {

      txtEventLog.Text = e.Entry.Message

        + System.Environment.NewLine

        + txtEventLog.Text;

    }

This will take the latest event log entry, and add it to the text box. Note I put it first, then add back what was already in the text box. This way the most recent event will always be at the top.

That’s it for this part, now everytime something is written to the event log, the EventLog component will catch the event and let us know about it.

Nice, but sometimes you also want to know what’s already there in the log. Instead of using a component let’s see how to do this with code. First, add a “using System.Diagnostics” reference to the header of your class (form).

Now, I think it would look nice when the TLManager loads to already have the text box populated with the past events. The System.Diagnostics library contains an EventLog class we can use to create an object for our particular event log. Once that’s done, we can cycle through the Entries collection to read what’s there. Here’s some code I added to the TLManger_Load event to do just that.

      StringBuilder sb = new StringBuilder();

      EventLog atl = new EventLog(“ArcaneTimeLogger”);

      for (int i = atl.Entries.Count – 1; i > -1; i–)

      {

        sb.AppendLine(atl.Entries[i].Message);

      }

      txtEventLog.Text = sb.ToString();

I start by creating a string builder object to hold all of the events. Next, and the key is the EventLog atl… line. I pass in the name of our log so the atl object will know what log it belongs to.

Next you will see a for loop that cycles through the entries. Note I’m deliberately starting with the last entry, the most recent one, and counting down to the oldest one. This will ensure the most recent event appears first in the text box.

Finally, I copy the data we’ve built into the string builder into the text box. And that’s it, two ways to monitor event logs and pull their data into your application.

Windows Services in C#: Sending Commands to your Windows Service (part 7)

Yesterday we looked at starting and stopping your windows service from another application. It would also be helpful to be able to send other commands beyond the basic set of Start/Stop/Pause etc.

On the good side, there is an API through which it is possible to send a command to your windows service, fairly easily as a matter of fact. The down side is it’s a one way communication, through the built in mechanism it’s not possible to return any data. Even more limiting is the only data you are allowed to pass in is an integer, and it’s value must be between 128 and 255.

Even with those limitations, if all you need to do is execute a few simple commands the built in API can be more than enough to meet your needs.

To illustrate, we’ll expand the windows service we’ve been using as an example. We’ll add the ability to send a command that will force the event log to be updated immediately, rather than waiting on the timer to fire off its event.

First, we’ll add two items to the service. The first is a public enum. Strictly speaking we don’t have to use an enum, but it makes for more readability.

    // Must be int between 128 and 255

    public enum commands

    {

      LogIt = 255

    }

Next we’ll add a new method to the windows service called OnCustomCommand. This is an override to the base classes method. As you can see it first calls the base method, then checks the value of the integer that was passed in, in this case against our enum. If it finds a match, it calls the WriteToLog method immediately. (The WriteToLog was discussed yesterday, so I won’t reiterate here).

    protected override void OnCustomCommand(int command)

    {

      base.OnCustomCommand(command);

      if (command == (int)commands.LogIt)

      {

        WriteToLog(“Arcane LogIt:”);       

      }

    }

OK, that’s all that’s needed for the service. Let’s switch to our program, and add another button called LogIt.

[Pic of TLManager]

Now we’ll add a little code to the click event for the log it button.

    private void btnLogIt_Click(object sender, EventArgs e)

    {

      ServiceController sc = new ServiceController(“ArcaneTimeLogging”);

      sc.ExecuteCommand(255);

    }

Like in our other examples we create a reference to our service by creating a new ServiceController object and passing in the name of our service. Once we have an sc object we call the ExecuteCommand method. This allows us to send messages to a windows service.

Numbers 0-127 are reserved for windows, and are handled in the base class. 128 to 255 are there for your own use. In the example above I used 255 just to show that you could pass an integer value directly without using an enum.

One last small item, we don’t want the LogIt button to be enabled if our service isn’t running. We’ll add a little logic to the SetDisplay, Start and Stop methods to include setting the buttons enabled status properly. Here’s the updated routines.

    private void SetDisplay(ServiceController sc)

    {

      sc.Refresh();

      if (sc.Status == ServiceControllerStatus.Stopped)

      {

        btnStop.Enabled = false;

        btnStart.Enabled = true;

        btnLogIt.Enabled = false;

        lblStatus.Text = “Stopped”;

      }

      if (sc.Status == ServiceControllerStatus.Running)

      {

        btnStart.Enabled = false;

        btnStop.Enabled = true;

        btnLogIt.Enabled = true;

        lblStatus.Text = “Running”;

      }

    }

 

    private void btnStart_Click(object sender, EventArgs e)

    {

      ServiceController sc = new ServiceController(“ArcaneTimeLogging”);

      sc.Start();

      btnStart.Enabled = false;

      btnStop.Enabled = true;

      lblStatus.Text = “Running”;

      sc.Refresh();

    }

 

    private void btnStop_Click(object sender, EventArgs e)

    {

      ServiceController sc = new ServiceController(“ArcaneTimeLogging”);

      sc.Stop();

      btnStop.Enabled = false;

      btnStart.Enabled = true;

      lblStatus.Text = “Stopped”;

      sc.Refresh();

    }

And that’s all there is to it. Compile and reinstall your service, then launch your TLManager program. With the service started, click the LogIt button a few times then go into MMC and take a look at your event log. You should see a new message appear each time you click the LogIt button.

Windows Services in C#: Controlling Your Service from Another Application (part 6)

If you’ve ever used SQL Server, you know it comes with a little control program that allows you to start and stop the SQL Server service. Wouldn’t it be cool if you could write a small program to do the same with your service? Well you can, and today we’ll learn how.

Before we begin, I made a few little tweaks to the TimeLoggerService source code that will make it a bit easier to work with, and implement some of the things we’ll want to do in our control program.

    public TimeLoggerService()

    {

      InitializeComponent();

      // Set the timer to fire every twenty seconds

      // (remember the timer is in millisecond resolution,

      //  so 1000 = 1 second. )

      _timer = new Timer(20000);

 

      // Now tell the timer when the timer fires

      // (the Elapsed event) call the _timer_Elapsed

      // method in our code

      _timer.Elapsed += new

        System.Timers.ElapsedEventHandler(_timer_Elapsed);

    }

 

    private void WriteToLog(string msg)

    {

      EventLog evt = new EventLog(“ArcaneTimeLogger”);

      string message = msg + “: “

        + DateTime.Now.ToShortDateString() + ” “

        + DateTime.Now.ToLongTimeString();

      evt.Source = “ArcaneTimeLoggerService”;

      evt.WriteEntry(message, EventLogEntryType.Information);

    }

 

    protected override void OnStart(string[] args)

    {

      _timer.Start();

      WriteToLog(“Arcane Start”);

    }

 

    protected override void OnStop()

    {

      _timer.Stop();

      WriteToLog(“Arcane Stop “);

    }

 

    // This method is called when the timer fires

    // it’s elapsed event. It will write the time

    // to the event log.

    protected void _timer_Elapsed(object sender, ElapsedEventArgs e)

    {

      WriteToLog(“Arcane Timer”);

    }

In the class constructor, the only change I made was to change the time from 60 seconds (60000 milliseconds) down to 20 seconds (20000 milliseconds). To be honest I got tired of waiting on it to log for my tests.

Next, I created a “WriteToLog” method that handles the actual writing of a message to the event log. This code is identical to what was previously in the timer_Elapsed event, except I take a passed in message and append the current date/time to the log. Note one other change, I modified it to use the LongTimeString instead of ShortTimeString, so I could get the seconds to display.

I then modified the OnStart and OnStop to log start and stop messages for me, which is probably a good idea for your service to do too. Finally I modified the _timer_Elasped event where I’d taken the WriteToLog code from, and made a call to our new method. OK, that takes care of changes to the windows service.

Now, let’s add a new project to our solution. In the Solution Explorer, right click on the solution name and pick Add Project, then pick Windows Application. Note that we could do this with a command line app or class library as well, but for this demo we’ll use a windows form. I gave my new app the imaginative name of “TimeLoggerManager”.

I renamed the Form1 to TLManager, and allowed VS to rename all the occurances of Form1 for me. I’m now going to add a few basic controls, one label (lblStatus), and two command buttons (btnStart and btnStop). I’m also going to add a timer control, tmrRefresh. Set the timer to enabled and pick a reasonable time, maybe every 10 or 15 seconds (10000 or 15000 in the Interval property, remember it gets set in milliseconds as well).

In order to use some of the classes we’ll need, we must set a reference to the System.ServiceProcess assembly. Right click on the TimeLoggerManager and Add Reference, then on the .Net tab scroll down to System.ServiceProcess, click on it and press OK.

Now switch to code view on the form, and in the using area add a “using System.ServiceProcess” reference.

The first thing we need to do is find out what the status is of the service event. To do this we’ll first get a reference to our service by creating a ServiceController object, note in the “new” area we have to pass in the name of our service in order to get a reference to it. Once our object is created, I’ll pass it to a method that will set everything up for the form.  

      ServiceController sc = new ServiceController(“ArcaneTimeLogging”);

      SetDisplay(sc);

Set Display is a custom method I wrote, here’s it’s code:

    private void SetDisplay(ServiceController sc)

    {

      sc.Refresh();

      if (sc.Status == ServiceControllerStatus.Stopped)

      {

        btnStop.Enabled = false;

        btnStart.Enabled = true;

        lblStatus.Text = “Stopped”;

      }

      if (sc.Status == ServiceControllerStatus.Running)

      {

        btnStart.Enabled = false;

        btnStop.Enabled = true;

        lblStatus.Text = “Running”;

      }

    }

The first thing called is sc.Refresh, this will cause the ServiceController to update all of the properties in our sc object with the correct values. Next I can query the Status property of our SC object, and set my command buttons and labels appropriately.

Starting and stopping our service is just as easy, all we have to do is create an instance of a service controller object, and then call it’s Start or Stop method.

    private void btnStart_Click(object sender, EventArgs e)

    {

      ServiceController sc = new ServiceController(“ArcaneTimeLogging”);

      sc.Start();

      btnStart.Enabled = false;

      btnStop.Enabled = true;

      lblStatus.Text = “Running”;

      sc.Refresh();

    }

 

    private void btnStop_Click(object sender, EventArgs e)

    {

      ServiceController sc = new ServiceController(“ArcaneTimeLogging”);

      sc.Stop();

      btnStop.Enabled = false;

      btnStart.Enabled = true;

      lblStatus.Text = “Stopped”;

      sc.Refresh();

    }

Because you can also start and stop the service from other locations, like VS or the MMC, it’s important to keep the display in sync. In the event for the timer, all we have to do is create another reference and pass it to the same SetDisplay method so everything stays in sync.

    private void tmrRefresh_Tick(object sender, EventArgs e)

    {

      ServiceController sc = new ServiceController(“ArcaneTimeLogging”);

      SetDisplay(sc);

    }

Go ahead and give it all a try. Start your service, then check it in the MMC. Use MMC to stop the service, then watch the app automatically update to reflect the status.

Tomorrow we’ll look at sending commands to our windows service, then to wrap up the series we’ll look at integrating the event log into our application. Stay tuned!

Arcane Holiday

Today in the US we are celebrating Memorial Day, where we remember all of the soldiers who fell in battle. So let me first start by thanking the families and those men who sacrificed themselves for the greater good.

In keeping with the holiday theme, I thought I’d take a brief holiday from the Windows Services series and catch up on a few things.

First, there’s been an update to my favorite Windows add-on, TouchCursor. The new version fixes the issue I mentioned with Virtual PC’s. The only issue since I’ve run across is in using it with Visual Studio and DevExpress CodeRush add-in. CodeRush also wants to use the spacebar for activation. However, I was able to easily change the activation key from CodeRush to something else, and problem was solved. Check it out at http://touchcursor.com/ or see my initial review at http://shrinkster.com/pf4 .

Next, about a week ago I mentioned some great music to program to by a group called Midnight Syndicate. Shortly after posting I found out the Haunted Voices Radio podcast did an entire weekend of Midnight Syndicate, including playing their music and complete interviews. Check out Haunted Voices Radio at http://www.hauntedvoicesradio.com/modules.php?name=Content&pa=showpage&pid=6 or http://shrinkster.com/pf2 . Each banner ad is to a separate MP3 (the weekend was broken up into 2 hour chunks for easy downloads). I believe there are 17 in all.

Finally I have to confess to a guilty pleasure. I recently received a gift certificate to a book store, and used it to purchase “Windows Developer Power Tools” by James Avery and Jim Holmes. (Amazon link: http://shrinkster.com/pf5 )

If you’ve been reading my blog for a while you know I’m a “tool freak”, I love add-ins and tools for Windows and Visual Studio. As such I’ve been wanting this book for a while, but since I’ve already got a huge stack of books I’m still reading through I was having problems justifying yet another book. The gift certificate gave me just the opportunity I needed to get this cool new book. At over 1200 pages it’s chock full of toys, can’t wait to dig in!

Windows Services in C#: Controlling Your Service from Visual Studio (part 5)

In part 3 of this series I documented how to use the Microsoft Management Console to control your service and view the event log. But did you know you can do it right inside Visual Studio?

Inside Visual Studio, open the Server Explorer (I keep mine docked over on the left). Under any database servers you may have should be your computer, click the + symbol to expand the tree.

[Pic of Server Explorer]

Now you can see quite a few items, including Services and Event Logs. Expand the services tree, and let’s scroll down to our service, ArcaneCodeTimeLogger. Right clicking will show us the various commands available to us. Since the service is already running, you can pause or stop it.

[Pic of Services in Server Explorer]

Having this functionality right within Visual Studio makes it very easy when it’s time to debug and test your various methods such as OnStart, OnStop, OnPause, etc. But wait, there’s more!

Just as with services, you can also examine the event log. Scroll up to the event log node and expand it. If you read my earlier series on event logging (http://shrinkster.com/p6d), you know I suggest creating your own distinct event log instead of shoving everything into the Application log. Now you can see why, it makes it very easy to pick out the messages for your app. Expand the two nodes for our service and you can see the first part of the messages appearing in the tree.

[Pic of Event Log in Server Explorer]

To see the complete message, simply double click on it. It will appear, along with other associated data, in the Properties window of Visual Studio.

[Pic of Properties showing detailed EventLog Message]

One thing you should note, when you use Visual Studio to debug your Windows Service, VS “helpfully” hides a lot of your windows, including the Server Explorer. You can get it back though, simply go to the View and pick the Server Explorer to make it appear again.

Now, you may be wondering why way back in part 3 we went through the MMC (Microsoft Management Console) instead of doing it this way. There are often multiple ways to accomplish tasks, and it’s often useful to know them all. For example, let’s say you have your service installed on a users PC and need to stop it or look at its events. If you don’t have Visual Studio installed on the box, what are you going to do?

When you do have VS, using the Server Explorer from within Visual Studio can make it easy to develop and debug your Windows Services. Take a few minutes to explore it’s capabilities, so you’ll have a second way to work with your services.

Windows Services in C#: Debugging Windows Services (part 4)

In part 1 of this series I mentioned debugging a windows service was a little different than normal debugging of an application. Today we’ll look into how you can debug your windows service.

First, open Visual Studio and have your project loaded, if it’s not already there. Now go over to the MMC (as I described in part 3) and make sure it’s logging events.

Now comes the neat part. Under the Debug menu in Visual Studio, select “Attach to process…”. When the dialog below appears, you will need to check the “Show processes from all users” and “Show processes in all sessions” boxes. Now your list should update correctly.

Scroll down and look for the process with the same name as your executable, in my case it was TimeLogger.exe. Click on it, and the click the “Attach” button in the lower left.

[Picture of Attach to Service Dialog]

If all went well Visual Studio should shift to “Run” mode. Your code will be locked (sorry, no edit continue with windows services). But you can go in and create breakpoints, as I’ve done here (click on the pic to see a larger version of it):

[Pic of VS ready to debug]

Now sit back and wait a minute, when our service fires the _timer_Elapsed event it will fall into the standard debug mode you’re used to, as you can see below.

[Pic of VS stepping thru the service]

In the screen above you can see where I took one step and am now on the line of code “string message =…”. I have access to my locals, as well as the call stack and other debugging tools. From here I can do the normal debug tasks, including stepping or just hitting F5 to continue.

When you are done debugging and are ready to disconnect from the service, simply return to the Debug menu and this time pick “Stop Debugging” (or hit Shift+F5). Visual Studio disconnects you from the running service and returns you to normal code editing mode.

Resetting for another test is still a bit painful. You’ll want to stop your service, then in your Visual Studio Command Prompt window run InstallUtil, this time with the /u option to uninstall it. (instalutil /u timelogger.exe). Then you can build, then reinstall your service.

I said this yesterday, but I want to stress it again. If you are developing under Vista, it is vitally important you run VS Command Prompt as the Administrator (simply right click on the menu option and pick run as administrator). If you don’t do this, instalutil will fail every time.

And that’s how you debug an windows service. It’s not really that difficult, now that you know the steps involved.

Windows Services in C#: Adding the Installer (part 3)

OK, you’ve crafted your service, now you’re ready to install it so you can test. To do so you’ll need to create an installer for your project. However, you don’t create an installer in the traditional fashion.

Instead, switch to the “TimeLoggerService.cs [Design]” tab. Now in that big gray area right click, and pick “Add Installer”.

[Picture of Add Installer Menu]

Visual Studio will do some magic and you’ll have a new ProjectInstaller.cs added to your project. It also added a few new references to the solution. If the “ProjectInstaller.cs [Design]” tab is not up, bring it up, and click on the serviceInstaller1 item.

Let’s start by giving it a decent name, I chose ArcaneTimeLoggerServiceInstaller. Now for the Description property I entered “The Arcane Code Time Logging Service”. For DisplayName I gave it “Arcane Code Time Logger”. Finally, I’m leaving the StartType property to Manual, you may wish to alter this for your “real world” service.

Now go back and click on the serviceProcessInstaller1. We’ll change it’s name to ArcaneTimeLoggerServiceProcessInstaller. If you remember the discussion from part 1, you will recall a discussion about the security. Here in the Account property is where you will want to set that. Since all this sample does is a minimal amount of logging, I can go with a fairly low level of security and set to “LocalSystem”.

OK, we’re almost done. Right click the project name (in my case TimeLogger) and select properties from the menu. (Note, make sure to click the project, not the solution!) Now on the Application tab, under “Startup object” pick TimeLogger.Program. Now save everything and build your project.

Assuming your build was successful, you can now install and test your windows service. There are two ways to install, we can use the installutil.exe, or create a full blown MSI installer. Since we are just at the point of debugging, we will use the simple installutil.exe.

To preset all the pathing you’ll need for install util, we’ll need to open a Visual Studio Command Window. Start, All Programs, Microsoft Visual Studio 2005, Visual Studio Tools, Visual Studio Command Window. If you are running under Vista, STOP! Do NOT click on Visual Studio Command Window. Instead, right click and pick “Run as Administrator”. Again that’s for Vista, for XP just click since you likely have Admin rights.

The moral is without Admin rights InstallUtil fails every time, and it drove me up the wall trying to figure this out.

Now in the command window navigate to the bin\debug folder where your project compiled. Type in installutil TimeLogger.exe (or whatever you named your exe).

[Picture of Command Prompt]

If everything goes well, you s hould get the messages “The Commit phase completed successfully” and “The transacted install has completed”. Now let’s go see if we were successful.

Open the Microsoft Management Console (Start, Run, MMC)). When it opens, pick the Services and EventViewer snap-ins. Under Services, you should easily find the ArcaneTimeLogger, just double click on it and start it. Once it starts you can close the dialog.

Now head over to the Event Viewer. Click on the “Create Custom View”, to make it easy to find our log events. In the “Create Custom View” dialog, select “By source” and in the drop down check the ones for ArcaneTimeLogging. Click OK to close.

[Picture of Create Custom View]

Your view should now update to look something like this:

[Picture of MMC with our Events]

Congratulations, you’ve now coded and installed a basic windows service, and more over logged events from your service. This sample app we just created can serve as a basic template for all of your future windows services.

By the way, we should probably not get carried away with the euporia. Let’s take a moment and clean up. Return to the services area of the MMC and double click on our ArcaneTimeLogger. Now Stop the service, so it won’t be continually logging the time.

Now that it’s not running, let’s uninstall it. Return to the Visual Studio Command Window and simply type the command “installutil /u TimeLogger.exe”. The /u switch will tell InstallUtil to uninstall our service named TimeLogger.exe. And with that you’ve take care of your clean up work. Tomorrow we’ll talk a bit about debugging a windows service.

Follow

Get every new post delivered to your Inbox.

Join 104 other followers