Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

NetMX - a JMX port to the .NET world

5.00/5 (1 vote)
10 Mar 2008LGPL34 min read 1   269  
An introduction to NetMX - a lightweight .NET management solution.

NetMX.JPG

Introduction

Most of us when told about monitoring and management of Windows applications thinks about the same: WMI. It is a well-known technology. Broadly tested, independent of programming language and, what is most important, supported by a wide range of management applications. It not a surprise that WMI is also supported by the .NET Framework (the System.Management library). So, does it make sense to build your own solution with similar functionality? Before you answer, think about the following:

  • WMI support in the .NET framework is focused on using the provided management objects. Building your own providers is slightly complicated.
  • WMI is a heavyweight technology. Instantiating WMI objects costs a lot of memory and CPU cycles.

The idea

So, what should we do if we need a lightweight environment to manage only our own system (not, for example, a whole domain)? Or we need to quickly add remote management and monitoring functionality to existing .NET applications (e.g., a Windows service written in C#). WMI doesn't fit in such cases. I faced such problems myself. At first, I thought abut quickly building a dirty library to instrument objects using Reflection and publishing their operations and attributes remotely. Then I realized, that there is something similar in Java, and it's called JMX - Java Management Extensions [^]. I decided to create a .NET version of JMX - NetMX.

The goal

As I mentioned before, I needed to add monitoring and management functions to existing Windows services. One of its parts is an exporting component which takes data (messages) from the database and writes them into files on disk. I wanted to know how many messages (grouped by type) were exported since the service started. The component definition is a simple class like this:

C#
public class Exporter
{
    public void ExportMessages()
    {
        //Export...
    }
}

It this was a Java class, using JMX, I would be able to turn it into a so called standard MBean just by defining the following interface:

C#
public interface ExporterMBean
{
    int getType1ExportedCount();
    int getType2ExportedCount();
    ...
}

and implementing it in the Exporter class (here I omit the description of this implementation because it's trivial). I wanted to have the same functionality under .NET.

The implementation

I should write here some words to glorify the architects of the JMX specification. It is really amazing how powerful it is without losing any of its simplicity. It would be enough to mention, that it is so universal, that whole Application Servers are built upon the JMX microkernel (JBoss). Aware that those people were far more experienced than I, I decided to make the changes in the API as small as possible while porting JMX to .NET. Those which I decided to introduce are:

  • Other representation of attributes in standard MBeans. Properties are natural representation of attributes in .NET, and I decided to use them in place of the getXxx/setXxx naming convention.
  • The default and obligatory remote access implementation uses RMI in JMX. In NetMX, it uses .NET Remoting.
  • All the factories use configuration sections (System.Configuration) as their data source.
  • Callback interfaces were replaced by delegates. This is intuitive and more fits the .NET style.
  • Standard MBeans can become notification emitters when they define events in their management interface.

Micro case-study

Let's leave the above mentioned real NetMX usage scenario and try to start from an abstract functionality of a counter. A counter is a device which should have the following characteristics:

  • Allows to get or set step values.
  • Allows to increment it by step value.
  • Allows to change value by an arbitrary provided value.
  • Can be reset (its value is set to 0).
  • Notifies interested parties about changes of its value.

These requirements can be translated into the following specification of the MBean interface:

C#
public interface CounterMBean
{
    [Description("Gets or sets step value")]
    int Step {get;set;}
    [Description("Increments counter value")]
    void Increment();    
    [Description("Adds provided value to counter value")]
    void Add(int value);
    [Description("Resets counter")]
    void Reset();    
    [MBeanNotification("Counter.ValueChanged")]
    event EventHandler<NotificationEventArgs> ValueChanged;
}

The possibility of using the Description attribute is an extension to original JMX specification (it does not use annotations - the Java equivalent of attributes). Also, the way of defining the ValueChanged notification is unique to NetMX. In standard JMX, the class implementing CounterMBean would have to implement a NotificationEmitter interface by itself (or derive from a helper base class). Here, everything is done by a notification, and plumbing is provided by the container (MBean server).

The counter implementation looks like this:

C#
public class Counter : CounterMBean
{
    private int value;
    private int step;
    public int Step 
    {
        get { return step; }
        set { step = value; }
    }
    public void Increment()
    {
        value += step;
        OnValueChanged();
    }
    public void Add(int value)
    {
        this.value += value;
        OnValueChanged();
    }
    public void Reset()
    {
        value = 0;
        OnValueChanged();
    }
    public event EventHandler<notificationeventargs> ValueChanged;
    private void OnValueChanged()
    {
        if (ValueChanged != null)
        {
            ValueChanged(this, new NotificationEventArgs("Value changed", value));
        }
    }
}

It is all what we need to publish our counter functionality. The code which does this publication is also simple:

C#
IMBeanServer server = MBeanServerFactory.CreateMBeanServer();
Counter o = new Counter();
ObjectName name = new ObjectName("Counter:");
server.RegisterMBean(o, name);
Uri serviceUrl = new Uri("tcp://localhost:1234/MBeanServer.tcp");

using (INetMXConnectorServer connectorServer = 
    NetMXConnectorServerFactory.NewNetMXConnectorServer(serviceUrl, server))
{
    connectorServer.Start();
    Console.WriteLine("Press any key to quit");
    Console.ReadKey();
}

Of course, NetMX will provide a standard set of ASP.NET controls which can establish a connection with the server and let us control our counter remotely through HTTP.

Summary

The goals which I set when starting the NetMX project seem to be achievable. Although NetMX is far from completion, event now, it is clear that assumptions about performance (i.e., of creating management objects) and little coding effort to instrument existing classes are true. It should be once more repeated here that NetMX is not a competition for WMI. It is only an alternative way for those who feel overwhelmed by WMI and seek more lightweight (in all aspects) solutions.

Further development

The NetMX project is hosted in the CodePlex [^] portal. It is contiguously developed. The current version has still a proof-of-concept character, but the implementation of the base JMX APIs is slowly stabilizing. The current goal is finishing the implementation of all the API containers in the javax.management, javax.management.remote, and javax.management.remote.rmi packages.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)