Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Creating a System Monitor

  This is a utility that can host “monitors” and provide a means to communicate to the user in a configurable, extensible way.

Difficulty: Intermediate
Time Required: 3-6 hours
Cost: Free
Software:
Hardware:
Download:

 

Introduction

I lost one hard drive at home and two at the office in less than six months, and in each case the event log had included warnings of impending doom. I don't check event logs often, so the warnings went unnoticed. Utilities exist to monitor hard drive health, but it looks like USB hard drives aren't supported yet. This is a problem since I have three at home and two fairly important ones at the office.

The problem

Software exists to monitor my internal hard drives, but not the external ones. Drives on remote machines need to be monitored and alert me when their drives show signs of failure.

I would like other things monitored, too. System availability, hard drive space, and so on, need to be watched -- especially on critical systems. Utilities of all kinds exist to monitor these things, but maintenance and configuration of disparate utilities can be a hassle.

The solution

The solution is simple: A utility that can host “monitors” and provide a means to communicate to the user in a configurable, extensible way. Any number of “notifiers” can be associated with a “monitor” and new “notifiers” can be written to allow any kind of communication.

Figure 1 – System Monitor main window

The following Monitors are included:

  • Disk space: Watches for a configurable amount of free space on a hard drive.
  • Event log: Watches for entries in an event log for entries posted by a specified source.
  • Network availability: Notifies the user when the computer's network connection is lost or restored.
  • Ping: Pings a computer and notifies the user if a ping fails

The following Notifiers are included:

  • Balloon tip: Shows a balloon near the icon in the notification area (see image below).
  • Email: Sends an email to a user-configurable address.
  • Message box: Displays a message box to the logged-in user.

Requirements

The application will:

  • Host custom Monitors.
  • Provide an interface for custom Notifiers.
  • Provide a generic configuration system using the application's config file, allowing settings to be passed to Monitors and Notifiers.
  • Allow for the association of Notifiers to Monitors.
  • Provide two run modes for Monitors: Persistent and Scheduled.
    • Scheduled is run at a specified interval by the application.
    • Persistent is never run by the application.
  • Run Scheduled “monitors” at the interval specified in the configuration file
  • Allow on-demand execution of Scheduled Monitors.
  • Run in the notification area.

We will build this solution using Visual Studio 2005 Beta 2, specifically Visual C# Express, and at the end of this article I will point out some features that make Visual Studio 2005 a compelling choice over previous versions. To download Visual C# Express Edition Beta 2, or any of the other Express editions, visit http://msdn.microsoft.com/express.

Architecture

The architecture is simple: The MainForm class handles the loading of Monitors and Notifiers, which are types that implement IMonitor and INotifier, respectively. Monitors are added to Tasks, which are responsible for running the Monitors on a schedule and maintaining status information. The MainForm displays information maintained by the Tasks and provides a means for executing a Monitor on demand.

The application configuration file plays an important role. It indicates which Monitors to load, which Notifiers should be associated with them, and what settings apply to both. The application itself is just a host and wouldn't do anything without the Monitor/Notifier definitions contained in the configuration file.

A typical Monitor definition is shown below. It represents a DiskSpaceMonitor, is run every four minutes and watches the C drive for free disk space below 10,000 megabytes. The Monitor has two Notifiers associated with it: A MessageBoxNotifier and an EmailNotifier. The former doesn't have any settings and the latter has three.

<monitor runFrequency="00:04" type="SystemMonitor.Monitors.DiskSpaceMonitor,SystemMonitor">
<settings>
<setting name="driveLetter" value="C" />
<setting name="freeMegabytes" value="10000" />
</settings>
<notifiers>
<notifier type="SystemMonitor.Notifiers.MessageBoxNotifier,SystemMonitor" />
<notifier type="SystemMonitor.Notifiers.EmailNotifier,SystemMonitor">
<settings>
<setting name="host" value="mail.someDomain.com" />
<setting name="to" value="someEmail@someDomain.com" />
<setting name="from" value="someEmail@someDomain.com" />
</settings>
</notifier>
</notifiers>
</monitor>

Implementation

Startup

The application configuration file is read. Monitors and Notifiers are created and their settings are passed to them in their respective Initialize methods. Notifiers are associated with Monitors and Monitors are assigned Tasks.

Normal operation

Persistent Monitors are responsible for their own operation and are left to manage themselves. Tasks for scheduled Monitors invoke the Monitors' Execute methods on a new thread at the interval specified in the configuration file. The MainForm's display is updated as scheduled Monitors run and allows for the explicit execution of a Monitor via context menu.

Technology highlights

All of the following are new in version 2 of the .NET Framework.

ListView grouping

ListView grouping is easy to use and can make the display easier to read on Windows XP and Windows Server 2003 operating systems. Groups are created by adding ListViewGroup items to a ListView's Groups collection. ListViewItems are added to groups by assigning their Groups property the value of an existing ListViewGroup.

NotifyIcon balloon tips

Displaying a balloon tip on a notification icon is as easy as calling a single method: NotifyIcon.ShowBalloonTip. Clicked, Closed and Shown events are also available.

Figure 2 – NotifyIcon balloon tip

New configuration section handling

Previous versions of the .NET Framework required manual parsing of custom configuration sections. Version 2 includes completely revamped configuration handling, using strongly-typed class access.

Visual C#

class MonitorElement : ConfigurationElement
{
[ConfigurationProperty("runFrequency")]
public TimeSpan? RunFrequency
{
get { return (TimeSpan?)base["runFrequency"]; }
set { base["runFrequency"] = value; }
}

[ConfigurationProperty("type")]
public string TypeName
{
get { return (string)base["type"]; }
set { base["type"] = value; }
}

[ConfigurationProperty("settings",
IsDefaultCollectionProperty = false)]
public SettingElementCollection Settings
{
get
{ return (SettingElementCollection)base["settings"]; }
}

[ConfigurationProperty("notifiers",
IsDefaultCollectionProperty = false)]
public NotifierElementCollection Notifiers
{
get { return (NotifierElementCollection)base[
"notifiers"]; }
}
}

Visual Basic

Class MonitorElement
Inherits ConfigurationElement

<ConfigurationProperty("runFrequency")> _
Property RunFrequency() As Nullable(Of TimeSpan)
Get
Return CType(MyBase.Item("runFrequency"),
Nullable(Of TimeSpan))
End Get
Set(ByVal value As Nullable(Of TimeSpan))
MyBase.Item("runFrequency") = value
End Set
End Property

<ConfigurationProperty("type")> _
Public Property TypeName() As String
Get
Return CStr(MyBase.Item("type"))
End Get
Set(ByVal value As String)
MyBase.Item("type") = value
End Set
End Property

<ConfigurationProperty("settings", IsDefaultCollection:=False)> _
Public ReadOnly Property Settings() As SettingElementCollection
Get
Return CType(MyBase.Item("settings"),
SettingElementCollection)
End Get
End Property

<ConfigurationProperty("notifiers", IsDefaultCollection:=False)> _
Public ReadOnly Property Notifiers() As NotifierElementCollection
Get
Return CType(MyBase.Item("notifiers"),
NotifierElementCollection)
End Get
End Property
End Class

Improved SMTP support

Simple SMTP support in previous versions of the .NET Framework was dismal. IIS was required, as was its SMTP component, which was no picnic to correctly configure. I stumbled upon the new SMTP support recently and it was a wonderful surprise. The snippet below just works. No configuration necessary!

Visual C#

SmtpClient mailClient = new SmtpClient();
mailClient.Host = _host;
mailClient.Send(_to, _from, title, message);

Visual Basic

Dim mailClient As New SmtpClient()
mailClient.Host = _host
mailClient.Send(_to, _from, title, message)

Network

A whole new namespace exists within System.Net: NetworkInformation. The Ping and NetworkChanges classes are used in this sample. Many more are available and worth checking out.

Generic collections

It's no mistake that System.Collections.Generic has replaced System.Collections in class templates. Two of the more significant, related benefits:

  • No longer need to write strongly-typed collections (most of the time).
  • Increased type safety over the standard collections.

The result is less time spent writing code and fewer runtime errors. What more could you want?

Nullable types

Representing the absence of a value type's value has been an issue since .NET 1.0, and people have solved it in very different ways. The generic Nullable structure provides a way for value types to have null values.

Both Visual Basic and C# can use the generic Nullable structure, but only C# has a new type modifier: A question mark appended to the type name.

In the example below, all expressions evaluate to true.

Visual C#

int? int1 = null;
if (int1 == null)
MessageBox.Show("null");
if (!int1.HasValue)
MessageBox.Show("has no value");
int1 = 10;
if (int1 == 10)
MessageBox.Show("equal");
Visual Basic
Dim int1 As Nullable(Of Integer) = New Nullable(Of Integer)
If Not int1.HasValue Then
MessageBox.Show("null")
End If
If Not int1.HasValue Then
MessageBox.Show("has no value")
End If
int1 = New Nullable(Of Integer)(10)
If (int1.GetValueOrDefault Is 10) Then
MessageBox.Show("equal")
End If

Easier threading with BackgroundWorker

The BackgroundWorker class joins the Thread, ThreadPool, asynchronous delegate invocation and friends in the world of .NET Framework-based threading. As with all things threading, a cursory overview isn't sufficient. Allocate some time to learn the BackgroundWorker class if you think you'll need threading support in the future. The design accounts for common usage scenarios and is a valuable tool for anyone's bag of tricks.

Follow the Discussion

  • TrentTrent

    This looks great Jeff, thanks.  Just what I was looking for, with a bit of work I think I can use this to do exactly what I need...once again, great work!

  • jalpesh vadgamajalpesh vadgama

    good work.. can i use background thread worker component to scan registry. If you have any example then please let me inform

  • System MonitorSystem Monitor

    There is a nice solution from sysmon, you can use their system monitor and add script in order to create actions and behavior.

    You can also use their SDK in order to code plug inns yourself...

    try it out.

    Jhon.

  • ScottMcKeownScottMcKeown

    This is a really neat application and thanks for sharing. However, could you use this to monitor drives on other PC's or ever servers?

    If so how, I have tried entering a server address in the App.config but nothing.

  • J-BJ-B

    Hi There,

    I just downloaded the projekt and wanted to publish and installit to get an idea of what's given.

    Build and Publish run without error in VS2k8 (had to convert the project to open it).

    But when I install it I get following error:

    * Activation of C:\build\SystemMonitor.application resulted in exception. Following failure messages were detected:

    + Exception reading manifest from file:///C:/build/SystemMonitor.application: the manifest may not be valid or the file could not be opened.

    + Deployment manifest is not semantically valid.

    + Deployment manifest requires that you specify a publisher and a product."

    I'm new to VS2k8 and never had that Error in 2k5, so help me out please!

    Thanks

  • ClaytonClayton

    Nice little app!

    Given its extensibility, it would be great if the "engine" were de-coupled from the GUI, so that it could be run in a service/background context.  This would rule out any interactive/GUI sort of notifiers, but all non-GUI ones would still be possible.. e.g. smtp, ftp, http, message queue, etc

    I am looking for something simple and robust like this to run on some non-production servers, but need the option to run as a service rather than a Windows app

    Nice work though... clean code Smiley

  • PaoloPaolo

    Hello, any news about the forthcoming release?

    I have seen an interesting project (http://polymon.codeplex.com/) so I would like to know which one should I try to learn.

  • SKSK

    Very nice and neat application.

    Whether BackgroundWorker works in windows service as well?

    Is the code decoupled from GUI is available?

  • Clint RutkasClint I'm a "developer"

    @SK you can use a BackgroundWorker in a window service.

    This is an old project so I can't remember if it is or isn't.  Shouldn't be too hard to decouple the two if they aren't properly abstracted out.

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.