A short while ago, I was working on the architecture of a large system that needed to perform a variety of “tasks”…specific actions that could be triggered by the user or run internally by the system through code according to a prescribed recipe or set of conditions. The issue at hand was, the variety of these widgets that would ultimately be implemented was not known a priori. In addition, the functions to be run needed to be
-
Data driven…actions and functional code outcomes needed to be based upon information in a database
-
User configurable at run-time…each function or action did not simply execute in the absence of custom user inputs, but could be scheduled or otherwise configured. For example, “send a message and attach this specific document to that message”.
-
Persisted…essentially the custom actions could be planned, added, or removed from a list at any time so we’d need to perform CRUD operations to store and edit instances of each custom action.
-
Extensible post-rollout…the application was going to be delivered in phases with planned enhancements delivered via service packs or other update mechanisms over time. In addition, customers may wish to purchase custom coded widgets or develop their own. Constantly recompiling of the entire system to support new functionality was out of the question.
There are a variety of ways to address these issues in terms of architecture patterns but largely due to #4 above, I settled on a plug-in implementation pattern and fired up Google to have a look around. After sorting through a lot of theory, Marc LaFleur’s blog pointed me to two excellent discussions that Roy Osherove was kind enough to share with the world (please see Part 1 and Part 2 of his plug in discussion for the details on this implementation).
What Roy’s implementation example was missing for my purposes, was a mechanism to address issue #2 above. An extensible pattern is fine, but I needed to make that extensibility configurable at run-time. Each custom plug-in widget needed one or more custom UI elements to allow the user to configure data that would be used by the plug-in. A second issue I ran into is that each custom plug-in had its own unique configuration attributes and I wanted all plug-in instances to be persisted in a single data schema…I didn’t want to be doing schema additions or mods each time we rolled out a new widget. The class diagram below illustrates the mods I made to Roy’s approach to accomodate our needs.

There aren’t any substantive changes to the IPlugIn interface that Roy gives us…I changed the method name that invokes the plug-in instance and added Description and Name properties so we can tell the user what widget they’re working with at run-time.
The key changes I made are found inside the IPlugInContext interface. Also note that I added an IPlugInConfig interface that allows us to store and retrieve config information for a specific plug-in instance that has been created. The additional “finder” classes are utility classes to locate specific IPlugInContext or IPlugInConfig implementation classes and follow the same implementation pattern as Roy’s PlugInFinder class found in his example code here.
IPlugInContext…widget attribute storage and retrieval
Since our back end database for the system in question was SQL 2005, I had available to me the Xml database type, allowing me to validate the incoming data against a schema and more importantly allowing me to store a variety of configuration information for specific IPlugIn instances of different types in a single data schema. Xml is excellent for storing information when an exhaustive schema is not known in advance. If one widget type requires two parameter values and a second widget type requires three in order to run successfully, no problem. The database doesn’t care as long as the information comes in and is persisted in Xml format.
In my case, I left any attribute/parameter storage properties off the interface definition for IPlugInContext. It is up to the implementation class to broadcast what information is needed for a particular IPlugIn. Instead, I provided two method contracts (BuildParamsXmlFromObject and ParseParamsFromXml) that are responsible for converting property settings to Xml and vice versa when the IPlugIn instance settings are retrieved from the database. When implemented, BuildParamsXmlFromObject takes all the current context settings in the implementation class, formats them as Xml and returns this information in an object of type SqlXml , which is the .NET framework equivalent variable type for the Xml database type. ParseParamsFromXml accepts a SqlXml object from the data tier and loads the context object with the contained information, preparing it for use. The implication here is that the context not only carries the information needed for execution (as in Roy’s example) but it is also responsible for parsing and serializing it’s own parameters to/from Xml stored in the database.
IPlugInConfig…custom parameter values for IPlugIn instances
So how do we allow users to configure these custom widgets at run-time to either be persisted in the database or executed? Enter the IPlugInConfig interface. IPlugInConfig exposes two methods…GetActionConfig (returns SqlXml ) and LoadInternalControls (accepts XmlDocument). Both of the exposed methods use the IPlugInContext interface to do the heavy lifting. The intent is that IPlugInConfig be implemented on a UserControl that provides all of the UI elements needed to configure a specific instance of a given IPlugIn type. For example, a “Send Message” plug-in might have labels and text boxes for sender, recipient, message, and file attachments.
Within the application, various plug-in types are made known to the UI by the PlugInController and PlugInFinder classes using reflection, the user selects a plug-in type to configure and the UI dynamically loads the IPlugInConfig UserControl (using the PlugInController and ConfigurationFinder classes), allowing the user to specify information relevant to the new plug-in instance. When the user is done configuring the plug-in to run, the UserControl then uses the relevant IPlugInContext to roll it’s parameters into Xml and passes it off to the data tier for storage. Likewise, a specific plug-in instance can be retrieved from the database and loaded into this custom UserControl in the UI and either be edited or executed.
That’s probably enough information for now…in a follow-on post I’ll provide examples of the implementation with code etc.

[...] 16, 2008 by homebrutrout Last week I posted a rather verbose discussion of some modifications to a PlugIn pattern that I made to make each plug in configurable at [...]
Could you make the source code public? If it is already, then send the link?
Thanks for the nice article.