Runtime handler registration in .NET

I’ve been working on some home automation software in C# for a friend and hit a bit of a stumbling block the other day. I needed to be able to register some message handlers for this application at runtime.

To do this, one needs to use the reflection framework - this allows you to inspect the assembly types and metadata at runtime, and is useful for this type of thing. This isn’t exactly rocket science, and one can quickly throw together a quick example to discover each of the types that implement a given Interface/Subclass and make a method call to a static method on the class:

// Find all the types in this AppDomain that implement the IMessage interface
foreach (Assembly assembly in	AppDomain.CurrentDomain.GetAssemblies())
{
    foreach (Type type in assembly.GetTypes())
    {
        if( type.IsSubclassOf( typeof(MessageBase) ) )
        {
            MethodInfo method = type.GetMethod("ImplementsMessage");
            MessageType	msgType = (MessageType)method.Invoke(null, null);
            _messageHandlers.Add(msgType, type);

            // Query the type and see whatprotocol message it handles
            try
            {
                // If any bit of this fails, we'll fail silently which is OK
                ConstructorInfo constructor =	type.GetConstructor(new Type[0]);
                IMessage obj = (IMessage)constructor.Invoke(new object[0]);
                _messageHandlers.Add(obj.ImplementsMessage(), type);
            }
            catch
            {
                continue;
            }
        }
    }
}

The above example will call the static ImplementsMessage method on each class that is discovered that is a subclass of MessageBase.

This is well and goodly, but the problems start when you try and declare the ImplementsMessage in either an Interface or superclass. In this case, I have an Interface IMessage that I want all message handlers to implement. Interfaces and base classes are good, as we know, for defining a concrete contract to ensure that all of our classes implement the methods expected of them by the rest of the code - and are a key part of the design of this library.

Unfortunately, in any of the .NET languages - you cannot define static members in an object being inherited. Whilst the CLR can handle this, it’s a design decision made by the .NET team over at Microsoft to not support it in their languages, though it seems that this is one they’re looking at changing.

OK. So we can’t define a static method, which isn’t nice and elegant - but surely we can drop the static constraint and use the above code? Well, err… perhaps

In .NET, the CLR transparently sends an object reference to every method call made. The obvious exceptions are calls to a constructor when instantiating a new method, and calls to static methods. So it’s imperative in the case above that we can always instantiate the object before we call the ImplementsMessage method.

This seems well and good, until you realise that .NET does not guarantee a default constructor as used in the example above. No, really - it doesn’t. This might sound contradictory to some people, as the C# compiler will automatically create one for you if you use it on a fully qualified type at compile-time, but not at runtime.

That means the above sample will only work in the case you have explicitly defined a sane default constructor on your class at compile time. This is bad because we can’t enforce this implementation with inheritance - so we’re in the same problem as before: programming by convention rather than contract.

Fortunately there’s a solution, and it’s nowhere near as long winded as the explanation up until now. I cheekily hinted at it at the start of the article, and the answer is Custom Attributes.

Attributes are metadata you can attach to structural objects in .NET assemblies that can be reflected at runtime. If you’re doing .NET, you’ve used them without realising. They’re used heavily by components to provide information for the Visual Studio designer, are used to assign versioning and copyright information to the final assembly files as well as many other places within the framework.

By creating a custom attribute class, you can mark your classes, structs, enumerations and the like with strongly typed data that is available at runtime. This sounds like an excellent solution to the problem at hand! Here’s the custom attribute class I wrote:

[AttributeUsage(AttributeTargets.Class,AllowMultiple= true,Inherited=false)]
public sealed class HandlesMessage : Attribute
{
    readonly MessageType msgType;
    
    public HandlesMessage( MessageType inType )
    {
        this.msgType = inType;
    }
    
    public MessageType HandledType
    {
        get
        {
            return this.msgType;
        }
    }
}

The updated code fragment to register these types at runtime:

foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
    foreach (Type type in assembly.GetTypes())
    {
        if( type.IsSubclassOf( typeof(MessageBase) ) )
        {
            // Look for the attribute saying what message they handle
            foreach (Attribute attr in type.GetCustomAttributes(false))
            {
                if (attr.GetType().Equals(typeof(HandlesMessage)))
                {
                    HandlesMessage hAttr = (HandlesMessage)attr;
                    _messageHandlers.Add(hAttr.HandledType, type);
                    break;
                }
            }
        }
    }
}

And here’s a message handler being tagged:

[HandlesMessage(MessageType.InterfaceConfiguration)]
public class InterfaceConfigurationMessage : MessageBase
{
    // ...
}

And there you have it! It’s a different paradigm, but still enforces the message to implement to the MessageBase contract as well as having to “register” to be picked up at runtime.

The message class itself will have to implement a few interface methods from IMessage to construct new objects, so in this case it’s arguable that that might be just as valid a solution - but that has its own caveats.

For now, it’s an elegant and simple way of registering message handlers in the application without relying on convention to ensure the message handler will behave as expected - and I’ve already had another opportunity to use custom attributes at my work to maintain backwards compatibility with some code that is being backported.

That’s all for now - a more general update to come and no doubt some more C# and .NET examples too, as well as some iOS related items.