Resilient Plugins Part Deux - Granular Control

code 0 comments suggest edit

Plug I got a lot of great feedback from my post on Building Plugins Resilient to Versioning, which proposes an event-based self-subscription model to plugins.

Craig Andera points out that we can get many of the same benefits by having plugins implement an abstract base class instead of an interface. This is definitely a workable solution and is probably isomorphic to this event based approach.

Dimitri Glazkov was the voice of dissent in the comments to the post pointing out that the application loses granular control over plugins in this approach. I was not convinced at the time as I was focused on keeping the surface area of the plugin interface that is exposed to the application very small. When the surface area is small, there is less reason for the interface to change and the less reason to break the interface.

However a simple thought experiment makes me realize that we do need to have the application retain granular control over which plugins can respond to which events. This is the scenario.

Suppose our plugin framework defines three events, MessageSending, MessageSent, MessageReceiving and someone writes a plugin that responds to all three events. Later, someone else writes a plugin that only responds to MessageReceiving. If the blog user wants to chain the functionality of that plugin to the existing plugin, so that both fire when a message is received, then all is well.

But suppose this new plugin’s handling of the MessageReceiving event should replace the handling of the old plugin. How would we do this? We can’t just remove the old plugin because then we lose its handling of the other two events. Dimitri was right all along on this point, we need more granular control.

It makes sense to have some sort of admin interface in which we can check and uncheck individual plugins and whether or not they are allowed to respond to specific events. However, this is not too difficult with the event based approach.

.NET’s event pattern is really an implementation of the Observer pattern, but using delegates rather than interfaces. After all, what is a delegate under the hood but yet another class? When any code attaches a method to an event, it is in effect registering a callback method with the event source. This is the step where we can obtain more granular information about our plugins.

In the Application that hosts the plugin, events that require this granular control (not every event will) could be defined like so.

private event EventHandler messageReceived;

public event EventHandler MessageReceived

So when adding and removing the event, we register the plugin with the system and then we add the event to some internal structure. For the purposes of this discussion, I’ll present some simple implementations.

void AddEvent(EventHandler someEvent)
    //We could choose to add the event 
    //to a hash table or some other structure
    this.messageReceived += someEvent;

void RemoveEvent(EventHandler someEvent)
    this.messageReceived -= someEvent;
private void RegisterPlugin(Type type)
    //using System.Diagnostics;
    StackTrace stack = new StackTrace();
    StackFrame currentFrame = stack.GetFrame(1);
    Console.WriteLine("Registering: " + type.Name 
         + " to event " + currentFrame.GetMethod().Name);

private void UnRegisterPlugin(Type type)
    StackTrace stack = new StackTrace();
    StackFrame currentFrame = stack.GetFrame(1);

    Console.WriteLine("UnRegistering: " + type.Name 
        + " to event " + currentFrame.GetMethod().Name);

As stated in the comments, the AddEvent method attaches the event handler in the standard way. I could have chosen to put it in a hash table or some other structure. Perhaps in a real implementation I would.

The RegisterPlugin method examines the call stack so that it knows which event to register. In a real implementation this would probably insert or update some record in a database somewhere so the application knows about it. Note that this should happen when the application is starting up or sometime before the user can start using the plugin. Otherwise there is no point to having access control.

public void OnMessageReceived()
    EventHandler messageEvent = this.messageReceived;
    if(messageEvent != null)
        Delegate[] delegates = messageEvent.GetInvocationList();
        foreach(Delegate del in delegates)
            if (EnabledForEvent(del.Method.DeclaringType, 
                del.DynamicInvoke(this, EventArgs.Empty);

Now, when we invoke the event handler, instead of simply invoking the event, we examine the delegate chain (depending on how we store the event handlers) and dynamically invoke only the event handlers that we allow. How is that for granular control?

In this approach, the implementation for the application host is a bit more complicated, but that complexity is totally hidden from the plugin developer, as it should be.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.



6 responses

  1. Avatar for Joe Brinkman
    Joe Brinkman July 1st, 2006

    I tried posting to your earlier blog, but a RSS Reader problem trashed my post so I will try again here.
    Often when people talk about interface based programming (whether they are talking about interfaces or abstract classes is immaterial) they focus on the syntactic nature of the interface and tend to ignore the semantic nature which is not as well defined.
    In your previous blog, you talked about replacing the use of interfaces to define extensibility points and instead use an event based approach. Unfortunately, this approach only addresses part of benefit provided by interfaces (both Interfaces and abstract classes), and that is that an interface not only defines individual methods, properties and events, it also defines a "group" of these constructs.
    Quite often, when building plugin frameworks with an interface, I expect a plugin to provide several properties, methods or events to properly function. Seldom do I write an interface that is "choose one of the above" from a list of methods. Often I need the plugin to implement all, or most of the defined interface in order to properly function.
    With an interface I can group methods and it becomes very clear to the programmer that he is expected to "do something" with each defined portion of the interface. A developer must take specific action to "do nothing" with a method by at least implementing a stub. This is enforced by the compiler and aids the developer.
    With an event based approach, this feature is lost. Any required dependencies between events is lost or must be recreated by the plugin framework. In addition, if implemented by the framework, it becomes a runtime check instead of a design-time/compile-time check which is less developer friendly.
    While I like the event based approach, I think it is wise to tread lightly and not be so quick to dismiss an interface based plugin architecture. Personally, I think both have their uses and depending on the nature of the extension, one may be a better fit than the other.

  2. Avatar for Haacked
    Haacked July 1st, 2006

    Good points Joe.
    As you pointed out, when implementing a plugin, an interface is a guide to the developer on what actions need to take place. Of course, even implementing every interface member doesn't guarantee it is done correctly as we cannot (in C# anyways) specify a contract and invariants on an interface. As you pointed out, a developer could stub out a stub method.
    With an event based approach, the only guidance a developer is given is that the event handler receives a parameter of a type that inherits EventArgs. This can also be a cohesive *interface*, but rather than implementing it, the plugin makes use of it to get its job done.
    By examining that type, they will get some semblance of what they are supposed to do with it in order to extend functionality.
    I think this works especially well when a plugin extends functionality and may be less suited for when it replaces functionality. In the latter case I may be more inclined to use a provider model.

  3. Avatar for davidacoder
    davidacoder July 2nd, 2006

    There was a presentation by Miller at PDC2005 that was excellent on add in architecturing and how you can deal with versioning there. The sessions are not online anymore, but I found the ppt here:
    Have a look, I think this applies to this problem.

  4. Avatar for davidacoder
    davidacoder July 2nd, 2006

    I looked around a bit more and found this blog on the System add-in work Microsoft is doing:
    Essentially they have a solution for managed add-ins that solves most of the difficult versioning, security, isolation etc problems. It ships with VSTA and will also be part of Orcas. You should certainly check this out if you are thinking about plug-ins!

  5. Avatar for October 26th, 2006

    You've been kicked (a good thing) - Trackback from

  6. Avatar for Adil Bangush
    Adil Bangush October 16th, 2007

    I am thankful to you, if you show the implementation of this plugin.