Once i came across a situation where I have to implement multiple logging mechanism in my application. Such as logging in database, event log, XML file etc. Not only that, but all of these should be independent to other. In other words, when I deploy my application, at some places I need only database auditing, some places only event log, some places both event log, database log and can be any combination. Now this will become a difficult task at first, because there are several different combination of it which my application suppose to handle. Not only that if I am going to add one more implementation of logging, such as streaming then I have to re-write the code of my application to handle this. I want to prefer a clean design that I wrote code once which will handle all current and future implementation of this. The first approach came to my mind is using reflection, but using reflection is not a good and clean design.
I decided two main principle for my application. First principle is all of my implementation must be in different component (DLL file). Second my application should look for one particular location on my file system to find the components and work accordingly depending on how many components are places on that location.
MEF came to rescue me to solve exactly the same problem. I used Directory Catalog of MEF to see the particular location in my file system and use ImporMany attribute to load multiple components and use their functionality accordingly. Here is a class diagram of different catalog provided by MEF.
We are going to use ImportMany attributes. This not the only attribute define in MEF here is a class diagram shows all the attributes define in System.ComponentModel.Composition namespace.
Import Many attributes define four new properties. Here is a class diagram of ImportmanyAttribute class.
Here CreationPolicy is an enum with three possible values Any, Shared and NonShared.
Our starting point is to define one logging interface. Just for simplicity I define a very simple interface with only one method in it.
Then in my container class, I define one IEnumerable type property and define ImportMany attribute on it. Here is a code of it.
constructor of our container class is very straight forward just created a directory catalog, composition container and composition batch. Here is a complete code of our container class.
Now comes to the implementation of this interface. I created a separate component, which implement this interface and export it. Here is a complete code of this.
I can make as many component as I want to provide different implementation of this interface. One implementation may log in database, other may log in event viewer, another one may log in file system, another one may stream the logging and so on. Just for simplicity my other implementation also write information on console window, but with slightly different message. Here is our second implementation of the same interface in another component.
Now comes to the client side. Using this container in our client is very straight forward. Just create an object of container class and traverse the container property using foreach loop and call the method for every component.
Here is complete implementation of our client.
If we copied both implementation components (DLLs) in the same folder where executable is (container dll to be more precise) It display the following message at the console window.
From Component 1 Message = Hello World
From Component 2 Message = Hello World
It shows that we are calling same method from both component. Now if we just remove one DLL from the same location then appropriate message will disappear. In future if we are going to write another implementation, then we simply implement this interface, export it and placed the DLL in the same folder, our program will automatically pick it.