Menu

Folder Monitor for the Notification Area

April 7, 2015 - .NET, C#, Programming, Windows

Recently I decided to collate minor annoyances or things that I felt annoyed me or disturbed my workflow, or things that could be helpful. The purpose was to come up with fairly simple “little things” that could be fixed with a nice, straightforward tool. Why? So I can write about it here and share the results.

Recently one of those minor annoyances involved Debug Logging. Not so much that logs weren’t being generated or I didn’t know where they were, but rather that, particularly with scheduled tasks, I might not be sure when they are being created. I also thought it might be useful to be able to see when configuration changes were applied.

The result of this was a fairly simple application concept- it sits in the background and will show a Balloon Tip if changes are detected in any of the specified folders. The nice thing about this is that pretty much everything we need is already part of the Framework- NotificationIcon for the Notification Area icons is already a .NET class; we can use FileSystemWatcher to watch the filesystem, etc- it’s merely a case of putting it all together!

The architecture

While in my particular use-case, I really only want to monitor one folder for changes, it seemed prudent to support multiple. Realistically speaking I have to deal with multiple debug folders across several profiles, particularly those that run as admin so I would likely end up needing to do so anyway. Hard-coding the file paths would be an obvious no-no, so we need to devise a reasonable way to deal with the configuration. My first thought was to make use of Elementizer, the XML Serialization library I constructed- if only so I could use it. But adding such a reference seemed unnecessary. I ended up instead sort of emulating that Library’s interface structure, though. I’d argue that this almost makes that library redundant, but much of what makes that library useful is the various helper capabilities it exposes to make adhering to it’s API contract easier- I just didn’t really need them as my needs were simple.

The FileSystemWatcher class can watch one Folder; since we want several, we’ll want to represent multiple monitor-able folders via separate instances of a given class. There are a lot of different approaches that could be taken here- the one I decided on was to have the configuration logic itself separated from the implementation. The configuration data would then be passed to the implementation, which would use the configuration information to construct and initialize the implementation to start “watching” those configured folders as configured. Here is the code for each particular Item:

Basically each configuration item is responsible for saving and loading it’s particular properties from and to a given XElement Node. It’s properties represent the various configurable settings that can be adjusted when constructing a FileSystemWatcher instance. The full configuration object that has a collection of each item is responsible for serializing and reading from an actual XML source file:

I feel it important to point out- as I believe I have done before, since I have a sudden feeling of deja-vu… that public interface properties and methods like “GetItems” is typically poor design; by returning the actual List object, the class yields ownership, in some sense, of that compositing instance. An alternative approach could be for MonitorConfiguration itself to extend from List<MonitorConfigurationItem> instead. (I may explore such design-oriented refactorings in future posts).

Otherwise, the purpose is fairly straightforward- it has a list of Configuration items and knows how to save and load them from an XDocument. static fields store the default configuration location, and instance fields store the specific location used by the instance, with a singleton available to access the standard default location (which in this case is a file in the common application data folder).

For the actual implementation, I wrapped each FileSystemWatcher within a different class. The reason I took this approach is because there seems to be some number of articles, bugs, and general issues with people using the FileSystemWatcher. This way, if necessary, I can change the implementation of the wrapper to use say a custom class using the ChangeNotification API functions, or a fixed version. I’ve not had any issues with the FileSystemWatcher in .NET 4.5.3, so it is possible the issues have been addressed.

Effectively it wraps the events and properties of the FileSystemWatcher. It manages it such that existing monitor is stopped and torn down and a new instance is created if one of the properties change, which would be easier than trying to maintain a list and replace existing instances in the list when properties change.

The core of the implementation is in a class I’ve titled “MonitorManager”. It’s task is to understand the configuration and be able to map them to the wrapper instances, in addition to capturing the events fired from the wrapper and then fire them back to the client code, passing back the actual firing Wrapper as an argument. This allows code to use the MonitorManager in a fairly straightforward fashion, simplifying the UI code I have in place. Also, because if this it should be fairly straightforward to revise the actual UI code to use different UI frameworks as well.

Restarting the monitor, which effectively disposes of all the file watchers and starts everything up with the given configuration again, is as straightforward as that- Dispose the existing one, then start up the new one and hook the events, then show a balloon tip indicating as much.

I’ve found it fairly useful to monitor a few debug folders. Some added features I think I may consider adding may include capabilities such as logging all such file changes. I suspect I may need to be careful of possible infinite loops whereby some sneaky individual sets the Monitor to monitor it’s own such log folder.

I have placed this new project onto github for posterity. I feel I should break from this to mention how exceptional VS 2013’s built-in git support is. Quite impressive. I only just tried it for the first time today, moving from my typical approach of just using the command-line. I’d even argue that it’s a better user experience due to being far more integrated than VisualSVN, which is also great but effectively just acts as a finite state machine for launcing TortoiseSVN.

Have something to say about this post? Comment!