After travelling for a year I was interest to see if MEF would work with MVC, and after some digging around I found it can.
***UPDATED****
Added a CastleWindsor example
With any MEF you’ll need a Composition Factory which in this case I’ll place in the MEF directory, but it can be in a different project if required.
public class CompositionContainerFactory { public CompositionContainer CreateContainer() { var path = HostingEnvironment.MapPath("~/bin"); if (path == null) throw new Exception("Unable to find the path"); var catalog = new DirectoryCatalog(path); return new CompositionContainer(catalog); } }
Now comes the interesting part, in MVC 3 Microsoft introduced the IDependencyResolver, which gets the services when needed.
So implementing the IDependencyResolver with MEF was a little trickier
public class MEFDependencyResolver : IDependencyResolver { private readonly CompositionContainer _container; public MEFDependencyResolver(CompositionContainer container) { if (container == null) throw new ArgumentNullException("container"); _container = container; } public object GetService(Type serviceType) { if (serviceType == null) throw new ArgumentNullException("serviceType"); var name = AttributedModelServices.GetContractName(serviceType); return Enumerable.Any(_container.Catalog.Parts.SelectMany(part => part.ExportDefinitions), e => e.ContractName == name) ? _container.GetExportedValue<object>(name) : null; } public IEnumerable<object> GetServices(Type serviceType) { if (serviceType == null) throw new ArgumentNullException("serviceType"); var name = AttributedModelServices.GetContractName(serviceType); return _container.GetExportedValues<object>(name); } }
The final step we will need to set the Dependency Resolver and this is done in the Application Start inside the Global.asax
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); DependencyResolver.SetResolver(new MEFDependencyResolver(new CompositionContainerFactory().CreateContainer())); }
Now we are ready to use MEF inside of MVC.
To use MEF inside of MVC just attach the [Export] attribute to controller and then import the object you require, like this:
[Export] [PartCreationPolicy(CreationPolicy.NonShared)] public class HomeController : Controller { [ImportMany] private List<IAddress> Addresses { get; set; } public ActionResult Index() { return View(Addresses); } }
Make sure that the Part Creation Policy is Non-Shared otherwise you will only be able to visit the page once.
That is it, what more could you want, oh the code samples, which I have update to MVC 5.2
CastleWindsorControllerInjection