Introducing: Extensibility Application Block
One of the demands from a successful application is the abilityto easily adept to the needs of its users if and when they change (and they do). Many times, the required changed, or extra features that need to be added require not only pure development work, but also re-compilation of some or all of the application binaries (this discussion does not include web applications, only winform applications).
To avoid having to go through this sometimes painful process just to add a simple feature, or fix a simple bug, a new need has grown - to allow extending an existing application without the need to recompile it or even without the help of the original developer. This is how what we know today as Add-ins and plugins were born.
When we moved into the world of .Net, we still have the ability to write applications that can be extended by others. However, there is no clear path, a common way, to design and implement such abilities into .Net applications. If you were to go today and try to build an extensible application, you'll be faced with a myriad of articles and HOW-TOs, each explaining the story a little bit differently than it's predecessor.
This Application block was created so that we can start and retain a common ground for how such abilities should be built. So that it can be both easy to understand and powerful enough as to be used by the most demanding applications.
The solution I present here is based on my experience writing extensible applications in .Net and on all the things I learned while trying to figure out the best way to achieve specific abilities while trying to maintain a generic approach.
How does it work?
There are 3 basic principles that need to be implemented in order for an application to have plugins:
1. | The application needs a way to recognize and communicate with the plugins |
2. | The Plugins need a way to talk (or sometimes control) the application in which they are hosted |
3. | The plugins need to be recognized and loaded at runtime into the host application |
|
This application block solves this problem by providing a common interface that all plugins must implement:IPlugin.
The principle is actually very simple:
Let's say I have a text editing application to which I would like people to be able to add plugins.
These plugins should be able to talk to the application in which they reside, AND the application should be able to talk to them.
However, since the application does not know in advance what plugins may be available (some of them may only be created in the future!) the application cannot have a direct reference on any specific DLL or class. It needs to support ANY CLASS but it needs to be able to talk to it on pre-known terms.
This paradox is solved by the using a COMMON INTERFACE that both the plug in and the application know. This interface is declared in a separate assembly and both the plug in and the application have a reference to that assembly.
This interface is what our application will use to communicate with the plug in. Any plug in that will want to attach itself to the app will have to implement this interface or otherwise we won't even try to load it. This interface is called (in this application block) IPlugin.
2. | The Plugins need a way to talk (or sometimes control) the application in which they are hosted |
3. | The plugins need to be recognized and loaded at runtime into the host application |
In the extensibility block there are special objects for which the only purpose in life if to find and load plugins. These are called Plugin Providers. Each plug in provider must implement the IPluginProvider interface. There are several providers already build for you. These include the XmlFilePluginProvider, SectionHandlerPluginProvider and DynamicFindPluginProvider. Each of these implements searching for plugins in a totally different way, but because they all support the same interface, they all return a collection of IPlugin object when they are done allowing you to simply choose the method in which to search.
Don't find anything you like in there? Feel like you need an extra feature? Simple implement the IPluginProvider interface in your own class and you're free to go.