MEF
MVC
Pluggable Architecture
Software Development
.NET

MEF with MVC 4 or 5 - Pluggable Architecture 2014

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

MEF, the Managed Extensibility Framework, can be used with ASP.NET MVC 4 or 5 to build a pluggable application where features are discovered and composed at runtime. This is a legacy stack today, but if you maintain an older MVC application and need modular loading of services or controllers, MEF is still a workable design.

What MEF Adds to MVC

A normal MVC application already has controllers, views, and some form of dependency resolution. MEF adds a composition model based on exports and imports.

That means you can:

  • define contracts in a shared assembly
  • export implementations from the main app or plugin assemblies
  • import those implementations into controllers or services
  • add new modules without editing the central wiring code every time

In a pluggable architecture, the most important design choice is what belongs in the shared contract assembly. Plugins should depend on contracts, not on each other.

Define a Stable Contract

Start by keeping shared interfaces in a contracts library referenced by both the MVC application and the plugin assemblies.

csharp
1public interface IMenuProvider
2{
3    string Name { get; }
4    IEnumerable<string> GetItems();
5}

A plugin exports that contract with MEF attributes.

csharp
1using System.ComponentModel.Composition;
2
3[Export(typeof(IMenuProvider))]
4public class ReportsMenuProvider : IMenuProvider
5{
6    public string Name => "Reports";
7
8    public IEnumerable<string> GetItems()
9    {
10        return new[] { "Sales", "Inventory", "Forecast" };
11    }
12}

This is the basic plugin unit: a class that can be discovered and composed without the main application hard-coding its type.

Build a Composition Container

In MVC 4 or 5, a common approach is to create one CompositionContainer during application startup. You typically compose parts from the main application assembly plus a plugin folder.

csharp
1using System.ComponentModel.Composition.Hosting;
2using System.Web.Mvc;
3
4public static class MefConfig
5{
6    public static CompositionContainer CreateContainer()
7    {
8        var catalog = new AggregateCatalog();
9        catalog.Catalogs.Add(new AssemblyCatalog(typeof(MvcApplication).Assembly));
10        catalog.Catalogs.Add(new DirectoryCatalog(@"C:\Plugins"));
11
12        return new CompositionContainer(catalog);
13    }
14}

The DirectoryCatalog enables pluggability because new assemblies can be dropped into the plugin folder and discovered at startup.

Compose Controllers or Services

Controllers are created by MVC, so MEF does not automatically inject them unless you integrate composition into the MVC creation path. One pragmatic legacy pattern is property injection with SatisfyImportsOnce.

csharp
1using System.ComponentModel.Composition;
2using System.Web.Mvc;
3using System.Web.Routing;
4
5public class MefControllerFactory : DefaultControllerFactory
6{
7    private readonly CompositionContainer _container;
8
9    public MefControllerFactory(CompositionContainer container)
10    {
11        _container = container;
12    }
13
14    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
15    {
16        var controller = (IController)base.GetControllerInstance(requestContext, controllerType);
17        _container.SatisfyImportsOnce(controller);
18        return controller;
19    }
20}

A controller can then import exported parts.

csharp
1using System.ComponentModel.Composition;
2using System.Linq;
3using System.Web.Mvc;
4
5public class HomeController : Controller
6{
7    [ImportMany]
8    public IEnumerable<IMenuProvider> MenuProviders { get; set; }
9
10    public ActionResult Index()
11    {
12        var items = MenuProviders.SelectMany(p => p.GetItems()).ToList();
13        return View(items);
14    }
15}

This is enough for a basic pluggable architecture: new assemblies export IMenuProvider, MVC composes the controller, and the controller sees all discovered plugins.

When MEF Is a Good Fit

MEF works best when you want discovery and late binding more than rich per-request dependency injection features. It is particularly suitable when plugins are optional and the application should remain functional even if a module is absent.

For new applications on newer .NET stacks, a modern DI container is usually simpler. For MVC 4 or 5 maintenance work, though, MEF remains a reasonable choice if the main problem is runtime discovery.

Common Pitfalls

A frequent mistake is letting plugins reference application internals instead of a small shared contract assembly. That destroys the point of the plugin boundary.

Another issue is expecting MVC to compose controllers automatically. Without a custom controller factory or dependency resolver, imports will remain empty.

A third problem is poor deployment discipline. If the plugin folder contains incompatible assemblies, composition failures are often discovered only at runtime.

Finally, treat MEF as a legacy-stack extensibility tool, not a universal DI answer. If you only need ordinary dependency injection, simpler patterns exist.

Summary

  • MEF can give MVC 4 or 5 a real plugin model based on exports and imports.
  • Keep shared contracts in a separate assembly and let plugins export those contracts.
  • Build a CompositionContainer at startup, often with an AggregateCatalog and DirectoryCatalog.
  • Integrate MEF with MVC through a custom controller factory or resolver.
  • MEF is strongest when runtime discovery matters more than modern DI features.
  • For legacy MVC maintenance, it is a practical pluggable-architecture option when used with clear boundaries.

Course illustration
Course illustration

All Rights Reserved.