Before I begin lets discuss about a common development scenario and how we might deal with it –
Suppose we have a requirement as follows (This was a real-time scenario once for me )-
- The system will collect table data from flat files, like – plain text (txt).
- The task is to collect column information and show the list of columns in a Grid.
Now, lets consider we have started our development process and also completed it and delivered. Your client is happy and so are you.
Now, comes the tricky part. A few days later your happy client asks –
could you please add an option so that we can also parse Excel WorkSheets, such as xls, xlsx, xlsm, xlsb files or may be delimited CSV files?
If you never anticipated this would happen, I assume you didn’t keep an option to add a parser later. Now what should you do? You will open the source again and modify it and them again build and deliver it. For a small project like this it is still troublesome, there are other projects with millions of lines of codes. What will you do with them? Open the source again and build?
Oh Boy, ain’t that tiresome!!!
Lets, talk about another approach –
Instead of hard coding the parser in the application could we could have done the following –
- Create a Plugin directory and keep a parser as a portable assembly (.dll) which will have a generic interface to expose methods.
- When executed the program will search for available plugins in that folder and will see that it has Text (.txt) file parser.
- Then the program will issue commands or all methods based on exposed interface of the parser.
Now, in this situation even if my client wants more parser, we can just build a new one implementing the base interface and build it as a class library and finally just put it in the Plugin folder and the parse will work out of the box.
Now, I think you have got a rough idea of what I am talking about. So lets, just mention it in words –
Using Managed Extensibility Framework(a.k.a MEF) we can do the above mentioned thing in minutes. In other words, we can inject business logic right into the application and will not even need rebuild it.
Before we start coding, you might wanna know where to get it. If you are using .net framework 4.0 you already have it and for those who are using 3.5, you can get the source from http://mef.codeplex.com/ and add a reference to the sources to get the feature sets. I haven’t tried with other versions of .net framework but if you still need to know, post me a comment and I will dig a little more deeper to get you the info.
We should create and organize out solution first.
Here is the basic process that I followed for this session –
- Open MS Visual Studio ( I am using 2010 ultimate and will use C# + .net framework 4.0 for this project) and create a Class Library project. I would name this project MEFIntro.Lib.
I use “.” extended project names to keep the names meaningful and easy to mange. Its not a restriction
- Remove the default class file “Class1.cs” from the project as we will not be needing this and we will create our classes ourselves.
- So far we have created the library project. We also need an executable project that we can use to show the output of the library. So lets add another project named MEFIntro.Desktop and this would be a Windows Forms Application. I also renamed the form to “MainForm“.
- Add a reference from MEFIntro.Lib to MEFIntro.Desktop.
- This is how your screen should look like –
- Now we will need one more project, that we will use to create Extensions. Lets name it MEFIntro.Lib.Ex.
- Add reference for the MEF library (System.ComponentModel.Composition) to both of your projects – MEFIntrol.Lib and MEFIntro.Lib.Ex.
- Our final solution will look like this. We have all the projects that we need for this tutorial. If more is needed we will add later–
The Extensible Core
Lets create the core section of our MEF Project.
By the by, I have downloaded and installed MS Visual Studio 11 Beta and loving it very much. So, from now on all other tutorials and blogs will be based on MS Visual Studio 11 Beta. Hope you will like the IDE too, its loaded with cool staffs….. 🙂
The core engine of our project will be responsible for the following tasks –
- Load all plugins and extensions those we will create and keep as plug & play components.
- Expose methods that our library will support.
- Provide Options and Interfaces for future plugin and extension development.
Okay, enough high level blabbering, lets jump into more low-level description. To support all the features mentions above we need to expose some interfaces, so that our extensions can inherit them and build their own logic in it, more like a strategic pattern. And at run-time our core engine will collect them using MEF and execute as needed.
When I said “interface” in above paragraph, I literally meant Interface of C# programming language. So don’t be afraid, we are inside the codes. Literally!!!
next, we need to expose some methods to be implemented in the implemented class. Our requirement is to collect column list i.e. metadata, from the files. So lets call this method “GetMetaData“. So our core engine interface will look exactly like the following –
public interface ICoreEngine
String GetMetaData(String filename);
So far, we have expose the interface that our extension methods and classes will use to integrate themselves with the engine. But we haven’t told your engine about the extensions. In other words, our engine still does not know that there could be extensions to use. So lets add 2 interfaces for that-
- The top-level interface of the extensions, all extensions targeting our engine will have to implement that interface, otherwise we will not consider as a plugin. I named it – IFileExtension. Our plan here is to use one extension class for one file of files. Like one class for .txt files and another extension class for .xls files. These classes will implement this interface.
- The second interface is for holding information about the extension classes. At run-time MEF will search with these data and give us the correct class to use. This idea will be much clear when you see the code in action. For now, lets just put a pin in it. I named this interface – IFileData
Now, we summarize what we have with a screenshot –
I prefer using a single file for all the interfaces that are under one namespace for all my projects, this helps me finding them later on. This is not a requirement. You are free to implement it your way as long as they all are available when needed.
So far we only have the abstract structure of our engine. But we need some concrete ones. Lets, look at our concrete implementation of our concrete core engine. I will describe the codes shortly –
Lets see what we have here –
- We have a concrete implementation of our core interface named CoreEngine.
- We have overridden the GetMetaData method. For now it is kept blank, we will add implementation logic later.
- The class also has some interesting fields, namely –
IEnumerable<lazy<IFileExtension, IFileData>> operations;
This is main container of all the plugins. At run-time the framework will automatically collect our plugins and put them in the operations field. All we have to do is call it in the appropriate manner.
- And one other interesting method ComposeParts.
This method does composition an puts together all the parts. you can understand the codes very easily by looking at it.
So, far we have nothing done with our implementation. Lets complete our core engine and call some extension methods. First we need to add at least one extractor class for this example. Lets add one for text ( .txt) files. The task is simple just open the files first line, split by the delimiter character and return the string array –
Now since we have one extension that we can call to test our implementation, lets finish the core. First we need to extract the file extension, then check whether we have any extractor defined for this extensions and if we do we will call it and return the value. Our final code for the GetMetaData will look like this –
That’s it, we have the core section complete.