Building a Plugin Architecture with C#

Written By: Nathan Baker

- 06 Mar 2006 -
















Description: I will show how to use C# to create an extensible application using plugins.

  1. Introduction
  2. Beginnings
  3. Let's Write Some Code
  4. The Host Application
  5. Writing a Plugin in C#

Writing a plugin in C#

The biggest problem with a plugin architecture is that you still have to kickstart it. Strangely enough, people don't start beating a path to your door to write plugins for your application unless your application is good enough to make them want to write a plugin for it, and it won't be good enough to justify that time expenditure until it does what it says it will do...in essence, you need to write your own plugin. Sometimes your plugin will just be a reference implementation, something that's 'good enough' until someone writes a better one. Other times your plugin will be very full-featured and others will use plugins to extend existing functionality (as is the case with most plugin-based media players). But regardless of which one it is, you will have to do some of the dirty work yourself.

So what are we waiting for? Let's add another project to your solution. Make another C# class library and name it CustomMathPlugin. Under the References folder, add a reference to the Interfaces project (like you did for the host application). Now you have a reference to the same interface definitions that the creator of the main app did. Oh, wait, that was you. Well, you have access to the same definitions that you did when you wrote the main app, and that has to be worth something, right? Finally, import the Interfaces namespace (using Interfaces;) to make use of this.

Inside the CustomMathPlugin namespace, create a class (I called it MyMathPlugin) and inherit from IMathPlugin like so:

public class MyMathPlugin:IMathPlugin

Also, we'll add the Plugin attribute to it, so now it looks like this:

[Plugin(PluginType.Math)]
public class MyMathPlugin:IMathPlugin

You may be wondering why it says [Plugin and not [PluginAttribute. Well, C# is smart enough to know that the Attribute part is implied, so you don't have to actually say that. Pretty slick, eh? If you're the cautious type, you can say [PluginAttribute(PluginType.Math)] and it will mean the same thing as the above. But why spend two seconds of your life doing all that extra typing when it's not even necessary?

If you're using Visual Studio 2005, you can mouseover the IMathPlugin part and say "Implement this interface", which will then generate method stubs for each function in the interface. If you still haven't succumbed to the praises I've been singing of Visual Studio 2005 and are stuck using an earlier version, you'll have to type the definitions yourself. Either way, your class should looks something like this when you're done:

[Plugin(PluginType.Math)]
public class MyMathPlugin:IMathPlugin
{
        public double Add(double a, double b) {
                return a + b;      }
 
        public double Subtract(double a, double b) {
                return a - b;      }
 
        public double Multiply(double a, double b) {
                return a * b;      }
 
        public double Divide(double a, double b) {
                return a / b;      }
 
        public string Name {
                get { return "Basic Math Plugin"; }
        }
 
        public string Version {
                get { return "1.0.0"; }
        }
 
        public string Author {
                get { return "Nathan Baker"; }
        }
};

Yeah, I know the code takes up a lot of space, but that's mostly just whitespace. You've already done the hard part (congratulations!), now it's just creating the brainlessly simple plugins. Feel free to change the author name from my name to your name (or some other name, I don't care). Also play around with the other text strings. Note that in a real application, the plugins may actually be more difficult to write than the GUI. Aren't you glad this is a fake application?

Patting yourself on the back

Assuming you did everything correctly (and with my impeccable guidance, how could you not?), you should be able to select your math plugin from the list box. You will be amazed to see...nothing happen! That is, unless there's a problem somewhere, in which case you will be greeted by a friendly "unhandled exception" error box. I guess I should tell you about the code that makes things happen. Don't worry, it's really simple. In fact, you could do it yourself. But since I'm still here, I might as well help you out:

private void lstPlugins_SelectedIndexChanged(object sender, EventArgs e)
{
        SetPluginInfo();
}
 
private void SetPluginInfo()
{
        Plugin P = lstPlugins.SelectedItem as Plugin;
        lblAuthorText.Text = P.Author;
        lblNameText.Text = P.Name;
        lblVersionText.Text = P.Version;
        lblPluginFilename.Text = P.Filename;
}

Actually, you could have done that yourself quicker than it took you to translate my goofy label naming scheme into your own. Also, if you copied and pasted then once again you will have to add the SelectedIndexChanged method to lstPlugins manually. Now you can see information about the plugin, which verifies that it is working correctly. If you want, you can also add some text boxes and buttons so you can make sure the math part works.

Before I head over to the next section, I want to illuminate one subtlety. You probably noticed that the plugins were displayed something like this:

M: E:\MyPath\MyPlugin.dll

How did that M: get there? For that matter, we're storing Plugin objects directly in the listbox, and they're showing up in a sensible manner. How does that work? Those of you familiar with the .NET framework or with Java are probably already smiling and nodding. You will notice that the Plugin class overrides the ToString() method. Containers like the listbox (along with the combobox and other components) call the ToString() method of whatever object you're storing in them. Clever, eh?

Outro

Well, now you have your very own example of how to write an application using a plugin architecture. I don't think that any of the techniques I used are exclusive to .NET 2.0, so if you're still unenlightened enough to be back using 1.1 or (God help you) 1.0, you may still be able to follow these instructions and have it work. For those who have 2005 (or the Express Edition), feel free to check out the code sample I included. It's been spiffed up a little, and also has an interactive interface so you can see the Math plugin in action. Note that you can use any .NET language to write plugins for this system, so if you're a VB.NET kind of person, give it a shot as well! I hope you had as much fun reading this as I did writing it, and feel free to hit me up with questions, comments, insults, offers of free money, etc. at []. Code to live!

<< Previous