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.
Beginnings
Since we're designing an application whose parts are necessarily decoupled, the solution file is going to be a bit more complex than your average single-project file. But that's OK; Visual Studio is designed for this type of work.
The first thing to do is to create a new solution. You do this by selecting File > New > Project. You want to create a C# Windows Application; I called my project PluginDemo. This will be the plugin host application. Later we'll add more projects that incorporate our plugins, but for now this is all we want in our solution.
The main form is created for you automatically and named Form1. This is completely lame and not at all suitable for our awesome application. I renamed my form to frmHost. If you rename the file in the solution explorer, Visual Studio 2005 is smart enough to ask you if you want to rename the class as well. Go ahead. In Visual Studio 2003 you will have to manually rename the class. When you do this in 2003 and try to compile/run, it will probably complain that it can't find Form1. Silly Visual Studio, that's because you renamed it! Go ahead and change all references to Form1 over to frmHost, or if you're feeling timid you can leave it as Form1.
Make the form larger and add a list box, a text box, a button, and a folder dialog. If you've been looking at the project file I included, you'll probably notice a lot more stuff on the form. We'll add that stuff later, but for right now we're focusing on the basics.
Defining your interfaces
Since you don't know what the code in the plugin looks like, how do you call it? The key is that the plugin has to conform to a certain interface. In other words, you tell the plugin writers "your plugin must have a function called PlaySound, and it should take a string as a parameter, which is the file name of a .wav file. That function should then open the file and play it, and then close the file." How they do that is up to them, but you have now given an interface specification.
The C# language already has a notion of interfaces. Unlike C++, C# only allows a class to inherit from at most one other class. Interfaces are a way around that. For those familiar with C++-style OO terminology, an interface is an abstract class that defines a series of pure virtual public functions that the derived class must implement. If what I just said made absolutely no sense to you, thats OK because you don't have to worry about it.
It is possible to make your interfaces exclusive to your host project, but we want to make it easy for other developers to write plugins. So we're going to add a new project with the definitions. Click File > Add > New Project... and choose a Visual C# class library. I named mine Interfaces and put the project folder inside the PluginDemo folder. Now rename the Class1.cs file to something cooler, like InterfaceDefinitions. Go ahead and delete the skeletal Class1 class that was automatically created for you, but leave the Interfaces namespace declaration the way it is.
Now we need to make sure that the PluginDemo project can see the Interfaces project. Under the Project Explorer, go to the PluginDemo folder and right-click on References. Click "Add Reference" and then click the Projects tab. Finally, select Interfaces from that list box and press OK. There you go, now you can access things in the InterfaceDefinitions file from PluginDemo. Since you don't want to be typing Interfaces.Whatever all the time, go to the top of your frmHost.cs file and add this line:
using Interfaces;
This will say that everything in the Interfaces namespace is now in the global namespace for that file. Yay!