Using MEF in MVC 3

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****

First you need to make sure your Visual Studio will accept MVC 3 this can be downloaded from Microsoft at http://www.asp.net/mvc/mvc3

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, here they are:

Using MEF in MVC 3.zip (845.26 kb)

I’ve been working on providing a full plugin for MEF and MVC, so I’ve rebuilt a sample in VS12 and sepatated  all the components.

Using MEF in MVC 3.zip (7.44 mb)

If you are interested in pulling out all the Views, content and JavaScript then it would be worth having a look at the RazorGenerator