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