Managed Extensibility Framework (MEF)
Below are my review notes from the 10-4 video on the upcoming Managed Extensibility Framework in version 4.0
- A new library available in v4.0
- Software entities should be open to extension, but closed to modification (Open/Closed Principle)
-
Basics:
- An application is built of parts or individual pieces composed together
- Three Steps:
- Export a part (Attribute: [Export(typeof(IMortgageCalculator))])
- Import a part (Attribute: [Import(typeof(Logger))])
- Compose a part
- Catalogs provide the parts (TypeCatalog, AssemblyCatalog, DirectoryCatalog, AggregatingCatalog)
- Container is the matchmaker
- Why? - Build a network aware app without changing the core window code (i.e. extend behavior without modifying code)
Sample
namespace Sample
{
public interface IMortgageRateRepository
{
public IList GetCurrentRates();
}
}
Notice that in the concrete implementation of the interface we use the Export Attribute
namespace Sample
{
[Export(typeof(IMortgageRateRepository))]
public class ELoanMortgageRateRepository: IMortgageRateRepository
{
public IList GetCurrentRates()
{
return new List();
}
}
}
Alot of stuff happening here, we use the export attribute at the class level and then the Import attribute
on our dependency. I also want to point out that we no longer 'new' up an object. Instead we implement the
IPartImportsSatisfiedNotification interface and move out binding logic to that event handler (basically we
can't use the objects until they have been imported by the container).
namespace Sample
{
[Export]
public partial class MortgageRates: Window, IPartImportsSatisfiedNotification
{
[Import]
IMortgageRateRepository MortgageRateRepository { get; set; }
public MortgageRates()
{
InitializeComponent();
//MortgageRateRepository = new MortgageRateRepository();
//grid.ItemSource = MortgageRateRepository.GetCurrentRates();
}
public void OnImportsSatisified()
{
Dispatcher.Invoke(new Action(() =>
{
MortgageRateRepository = new MortgageRateRepository();
grid.ItemSource = MortgageRateRepository.GetCurrentRates();
}));
}
}
}
Finally, where the magic happens. We create an AssemblyCatalog and then a CompositionContainer. Notice that
instead of 'Newing' up an instance of the window directly. We get an instance of the exported object from the
container.
namespace Sample
{
public partial class App: Application
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
var window = container.GetExportedObject<MortgageRates>();
//var window = new MortgageRates();
window.Show();
}
}