I am working on a plugin model on .net framework which is based on MEF or unity.
The problem is I haven’t found a solution to order plugin execution.
Suppose there exists an execution pipeline which is composed by plugins, there’re many kinds of relationships among these plugins: some plugins depend on another plugin that they could only be called after that plugin has been called. Some plugins should be called at the end of the pipeline etc.
The configuration file could be xml or anything else, it’s not important. The thing I am confusing is the order algorithm.
A dependent tree could solve, but I don’t know if it is enough. Is there any mature solution? Any open source project about this? Or any suggestion?
More explanation.
Suppose I am working on a text editor, this editor supports multiple plugins, after user finish his job and save, a plugin execution pipeline will be called. some plugins work on xaml ,some work on ubb code, and there’s a plugin transfer xaml to ubb.
So all plugins work on xaml should be called first, and then, call the plugin transfer xaml to ubb and then, call plugins work on ubb.
This is an example to plugin dependency and orderring, there may exist more complex relationships among these plugins.
So, how to solve this problem in a generic way?
I think what you are looking for is being able to sort by dependencies. I’ve used something similar whereby I’ve created a Bootstrapper object to manage application startup. This Bootstrapper supports 0 or more bootstrapper Tasks, which may or may not have dependencies. The way I tackled this was to create a new collection type, a
DependencyList<TModel, TKey>which allows you to add an arbitrary number of items, and it will automatically sort on first enumeration, or after any subsequent collection changes.In terms of what you want to do, we can take advantage of both this new list type, but also custom MEF export information. The first place we’ll start, is our base pipeline plugin contract:
I prefer to add an abstract class to accompany it, so if I need to, I can introduce some base shared logic without breaking existing plugins.
Next thing we’ll do, define the metadata contract, and then a custom export attribute:
With a custom export attribute, I can define the shape of my exports to ensure they are all exporting the correct information.
Next, let’s look at a custom plugin. Let’s assume we want to create a pipeline for applying BBCode adornments to our input text, so first, a simple plugin:
The above example, simply wraps the input text in the
[color]tags. ThePipelineattribute details a plugin name (ApplyColour), and what pipelines to make the plugin accessible to, in this casebbcode. Here is a more complex example:In the above example, I’m detailing two additional plugins, one that makes the text bold, and on that is italic. But, I’ve introduced a dependency requirement, and have told our plugin system, that
MakeItalicis dependent onMakeBold. This is how we put it together:Our
PipelineManagertype is powered by MEF, so it will[Import]a series ofIPipelinePlugininstances along with their associated metadata (which should be shaped to be projectable asIPipelinePluginMetadata). With that in mind, here it is in use:Really the dependency list, and your pipeline design are two separate areas to look at, but I hope this gives you an idea of how you could use it.
I’ve thrown this up as a Gist also (https://gist.github.com/1752325).