Creating a plugin architecture in .NET can be achieved in a few steps using the .NET framework. All it takes is a little time, a common interface and reflection. In this blog we’re going to look at how to make a simple plugin that performs basic integer calculations. As a disclaimer, this method is not CLS compliant. If that is necessary for you, then stick around and I hope to have a new version that maintains compliance posted.
The code in this blog is mostly illustrative, and the full code is available on CodePlex at the following link:
http://wtfnext.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=27051
Setting up a common interface
Our main console application has to know just basic things about our plugin. It doesn’t need to know any more about it than that it complies to an expected interface. For this example, our plugins must:
- Expose a class named Plugin
- The class must implement our common interface: IPlugin.
- The plugin must end in “Plugin.dll” and be present in the application directory.
If we get all of these done, we can connect to the plugin successfully. The first step is to define the IPlugin interface, which acts as the basic contract between any plugin and the console application. We’ll place this in its own project to compile into a separate DLL, so that we can easily reference it from our plugin projects.
Public Interface IPlugin
ReadOnly Property Name() As String
ReadOnly Property ActionName() As String
Sub Calculate(ByVal value1 As Integer, ByVal value2 As Integer)
End Interface
Consuming the interface according to our rules
So our calculation plugins will expose the name, what their action is and a calculate function that operates on two values. We can create an example plugin that performs addition:
Public Class Plugin
Implements IPlugin
ReadOnly Public Property Name() As String Implements IPlugin.Name
Get
Return "Addition"
End Get
End Property
ReadOnly Public Property ActionName() As String Implements IPlugin.ActionName
Get
Return "Add Values"
End Get
End Property
Public Sub Calculate (ByVal value1 As Integer, ByVal value2 As Integer) Implements IPlugin.Calculate
Dim result As Integer = value1 + value2
MessageBox.Show ("The result is " + result.ToString)
End Sub
End Class
See how we named the class that implements the plugin as just Plugin? This is because this is what the consol application expects. We can have other classes and whatnot in our plugin that do the meat of our work, but the application that consumes the plugin only cares that the possible plugin follow our rules stated earlier.
Checking and consuming the plugin
In our console application, all we’ve got to do is grab our possible plugins, then check their validity. Once we’re sure it is valid, we can consume it via the interface.
Dim asm As Assembly = Assembly.LoadFrom(possiblePlugin)
Dim myType As System.Type = asm.GetType(asm.GetName.Name + ".Plugin")
Dim implementsIPlugin As Boolean = GetType(IPlugin).IsAssignableFrom(myType)
If implementsIPlugin Then
Console.WriteLine(asm.GetName.Name + " is a valid plugin!")
Dim plugin As IPlugin = CType(Activator.CreateInstance(myType), IPlugin)
Console.WriteLine("{0}: {1}", plugin.Name, plugin.ActionName)
plugin.Calculate(5, 4)
End If
Wrapping things up
Well, this was a quick and dirty look at implementing your own plugin architecture into your application. Please leave feedback or questions. I’d be happy to hear both!