Getting Started with Multifile Assembly – Part II





5.00/5 (1 vote)
In this post, we will have more insights on the implementation part regarding multi-file assembly and using MEF to apply the concept practically in the applications using Directory Catalog technique.
Some Brief Before We Continue
Hi! In the last article on this topic here - MULTIFILE ASSEMBLY part – I, I talked conceptually about creating multi-file assembly and possible usages.
In this post, we will have more insights on the implementation part regarding multi-file assembly and using MEF to apply the concept practically in the applications using Directory Catalog technique.
Table Of Contents
- History on multiple file assembly
- What is MEF
- General Architecture of Extensible Application
- Implementing Windows Forms Application using MEF
History of Multiple File Assembly
To implement the multiple file assembly aka plug in application approach in the past was very tedious work (I believe multiple file assembly is which uses more than one assembly). Like in .NET application programs, we had to use Reflection and Dynamic assembly loading and types tactics which were not reliable, i.e., in case any exception happens in the referencing assembly while loading into main program, it would result in either a minor failure of a sub program or whole program leading to crash. However, today, we have a very good tool at hand from Microsoft, the name is Managed Extensibility Framework i.e., MEF in short name which I would be discussing in the next few paragraphs.
What is MEF?
The answer is MEF is a composition layer or class library for .NET that improves the flexibility, maintainability and testability of applications of any size. MEF is used for third-party plug in extensibility, or it can bring the benefits of a loosely-coupled plug in architecture to our applications. It also lets extension or plug in developers easily encapsulate code and avoid fragile hard dependencies between the applications. In the next section, we would be directly going to architecture overview and implementation information.
General Architecture of Extensible Applications
Here there are three major components:
- Main Assembly
- Infrastructure Assembly
- plug in Repository
Main Assembly
Main Assembly is comprised of UI and Wire Line or Skeletal code to combine the building block of the application. This defines the Features and Functional limits regarding extensibility of our application. Controlling the program flow and loading plugins from the repository such as from local directory or download from global repository and so on.
Infrastructure Assembly
In Infrastructure assembly, we have interfaces and abstract classes defined which stands for two purposes:
- Define the basic skeleton of the plugins assemblies which are to be plugged in the main application
- Enables the loose-coupling and balanced cohesion between the main program and plug in assemblies
We have to design and implement the Infrastructure assembly modules step before we start implementing the plug in modules, and design decisions are based on the features and extensibility of the application. It purely depends on the Infrastructure assembly that we do not have to recompile the main application assembly, in case of any changes to accommodate any new requirement or extensibility of the plugins into the Infrastructure assembly.
plug in Repository
In plug in Repository, we can have many different implementations based-on the Infrastructure assembly. Each and every plug in may or may not have all the types definition that we have in the Infrastructure design. The plug in repository can be online like Nuget Gallery and Atlassian JIRA or may be offline based on the needs of the application.
Implementing Windows Application using MEF
Here, we have one Visual Studio solution named “DynamicAssemblyApp
” and four projects in that:
DynamicAssembly.Infrastructure
– It is Infrastructure assembly.DynamicAssemblyApp
– It is Main assembly.DynamicAssembly.FedEx
– It is an plug in assembly for FedEx specific shipping implementations.DynamicAssembly.USPS
– It is an plug in assembly for USPS specific shipping implementations.
So How is this Application Loosely Coupled and How Plugins Work in Application?
Here, the layer diagram below shows the strong-coupling between the different assemblies. On closely inspecting, we can observe that the Main Assembly aka DynamicAsssemblyApp
does not have connector to any of the plugins we have created. We make it possible using the MEF to load the plug in assemblies at runtime into the infrastructure instance models in the main application’s memory.
How Does the Sample Main Application Look?
As we click the Load Assembly button, the application would lookup the plug in directory and load the different shipping methods into the main assembly and List them in the ListBox
control placed on the left-hand side.
Please note currently in MEF approach there is no easy way to unload the plugins once we have them loaded into memory as mentioned in one of the www.StackOverflow.com question here.
To understand the dynamism happening in the main assembly, I would like to show it in some steps as below:
- Define the
Export
orExportMany
in the plug in assembly on the class definition which inherits fromIShipping
type (only those classes which inherit fromInterface
defined in Infrastructure assembly can be marked asExport
, so application would know that where the plug in instance fits). - Define the location to load the dynamic parts into our application, i.e., a
public
variable or property of theInterface
type from the Infrastructure assembly. Here is theIShipping
type. - Define the trigger for loading the plugins such as:
- At the start up of main application in background thread so as to not slow down the startup time (recommended).
- On click of a button or dropdown selection (shown in the example).
- On File Directory changes with using some File System watcher.
- After the trigger, check the variable or property having the imports, and use in the application appropriately as per the requirements.
Please note: Import/ImportMany or Export/ExportMany can be based on three different ways
- String Key i.e.
[Export("MyTypeKey")]
. - Type Definition such as Interface, i.e.,
[Export(typeof(IInterface))]
. - Both from above (recommended, as this will help to uniquely identify the
Import
happening in the main application and we canImport
the target type in different forms from one plug in assembly and in less strict manner) i.e.,[Export("MyTypeKey", typeof(IInterface))]
.
Defining Export in plug in based on the type.
///
/// Define the FedEx method for Shipping
///
// Export attribute here declares that the assembly is,
// ready to provide this class to external application to use
[Export(typeof(IShipping))]
public class FedExShipping : IShipping
We import the plug in instances for FedEx and USPS Shipping Methods in Property ShippingList
in the main application and declaration is decorated with ImportMany
attribute which would import and instantiate all the class types inheriting from IShipping
interface from the plug in assemblies into the specified property.
// Defining the imports from the plug in directory.
// Using ImportMany as we would be loading all the assemblies,
// containing the Export for the specified interface type.
[ImportMany(typeof(IShipping))]
public List<IShipping> ShippingList { get; set; }
On click of the button ‘Load Assembly’, we trigger the loading of plugins assemblies from the plug in directory in the application directory. The code for this is as below:
///
// Clean up previous Shipping Methods.
lstboxShippingMethod.Items.Clear();
// Using the directory approach for plugging/loading the assemblies dynamically.
// DirectoryCatalog constructor takes the input filepath for the plugins
// Here it is in the application directory i.e. /bin/plug in/*.dll
var catalog = new DirectoryCatalog("plug in");
// Compose container using DirectoryCatalog instance
var container = new CompositionContainer(catalog);
// Finally load the plugins
// Here we might face exceptions in loading and exception information
// is usually in the InnerException of the Exception.
container.ComposeParts(this);
// If we found no Exports from the plugins for the Shipping Methods
// then return empty handed.
if (ShippingList == null) return;
// Iterate thru each of the shipping methods and add to the ListBox Collection
// PS: We could do many other sort of things with the Imported the Shipping List.
foreach (IShipping item in ShippingList)
{
lstboxShippingMethod.Items.Add(item.ShippingName);
}
The NameSpace
for ImportMany
attribute and DirectoryCatalog
are as below respectively:
using System.ComponentModel.Composition
using System.ComponentModel.Composition.Hosting
So getting in action:
- Rebuild the solution.
- Rebuilding solution will copy the FedEx assembly in the main application plug in directory automatically, as it is coded in the plug in’s Post-Build commands (see in Project’s Properties) to copy it there in the plug in directory.
- Execute the main application.
- Click the ‘Load Assembly’ button.
- FedEx would be listed in the
ListBox
. - Now copy manually the USPS plug in assembly (/bin directory contents) into the plug in directory.
- One more time, click the ‘Load Assembly’ button.
- This time FedEx and USPS both would be listed in the
ListBox
.
And we are done with the sample!
Download the sample application from SkyDrive here.
I hope this was pretty good to know & understandable regarding plug in applications and MEF. At the point now, I think that I would publish the MEF version of the HB Code application in future.
Do comment below regarding what you think about plug in applications and using MEF.
Keep reading and keep your thoughts coming out to the world.
Some Recommended Articles and Questions Regarding MEF and plug in Applications
- StackOverflow - How does MEF’s DirectoryCatalog work?
- CodeProject - An Introduction to Managed Extensibility Framework (MEF)
- MSDN - Managed Extensibility Framework (MEF) Overview
Related Articles
- Preferences from for MEF plug in
- plug in based development
- Implementing Chain of Responsibility Design Pattern in C# using Managed Extensibility Framework (MEF)
- Announcing the jQuery plug in Registry
- Introducing ForTea – a T4 templating plug in for ReSharper
- Log4net cannot find configuration file when run from Visual Studio/Microsoft Test Framework
