Export (0) Print
Expand All

How to: Use MEF with MVC

.NET Framework 4.5

This topic explains how to create an ASP.NET Model-View-Controller (MVC) app that uses the Managed Extensibility Framework (MEF). You can use MEF to connect the models, views, and controllers that make up the request-handling machinery of an MVC app. The app-specific objects that perform the business logic of the app can be represented as MEF parts. The MEF composition engine provides the MVC controller with complete, ready-to-use parts, and automatically handles disposal and teardown of those parts.

This topic assumes that you're familiar with the concepts discussed in the MEF overview.

Important note Important

The procedures in this topic require Visual Studio 2012 or later.

Starting with the Visual Studio 2012, Visual Studio includes a template that you use to create an ASP.NET MVC solution.

To create the MVC project

  1. In Visual Studio, create a new project of the type ASP.NET MVC 3 Web Application, and name it MEFMVCApp.

  2. In the New ASP.NET MVC 3 Project dialog box, choose Internet Application.

  3. Create a folder called Parts in your project. Parts are the basic unit of MEF composition, and can be used to provide all the app services not provided by the MVC app itself: accessing data, performing calculations, accessing other sites or services, and implementing your business logic.

In ASP.NET MVC apps, you use interfaces to define the contract that a part provides to other parts.

To export and import parts

  1. Open the shortcut menu for the Parts folder and add an interface named ILogger.cs. Add the following code:

    public interface ILogger
    {
        void Write(string text);
    }
    

    Any concrete classes in the Parts folder are assumed to be for managed composition. In MEF terms, these classes will be exported (see the MEF overview). By convention, any interfaces that are implemented by a part are assumed to be the contracts it wants to export.

  2. Open the shortcut menu for the Parts folder and add a class named TraceLogger.cs. Add the following code:

    public class TraceLogger : ILogger
    {
        public void Write(string text)
        {
            System.Diagnostics.Trace.WriteLine(text);
        }
    }
    

    This part will be exported under the contract type ILogger. To use this part in the MVC app, you can import it into the controller.

  3. Open HomeController.cs in the Controllers folder. Add a using statement for the namespace MEFMVCApp.Parts. Add the following member and constructors:

        ILogger _logger;
    
         public HomeController() : this(new TraceLogger())
          {
          }
    
        public HomeController(ILogger logger)
        {
            _logger = logger;
        }
    
  4. Add the following line to the body of the Index() method to demonstrate the TraceLogger:

    _logger.Write("MEFMVCApp: Executing the Index() action method.");
            
    

    Build and run the project. When the index page is displayed, the logged message appears in the trace window.

The MVC composition engine makes assumptions about what should be done with parts based on conventions. You can override these default behaviors by adding the appropriate MEF attributes to the parts.

To override default behavior

  1. In TraceLogger,cs, add a using statement for System.ComponentModel.Composition, and then add the following attribute to the class:

    [Export("myTraceLogger", typeof(ILogger))]
    

    HomeController will not be able to import TraceLogger, because their contract names no longer match.

  2. To add a contract name to the import, in HomeController.cs, add a using statement for System.ComponentModel.Composition, and then change the constructor in the class to the following:

            public HomeController([Import("myTraceLogger")]ILogger logger)
            {
                _logger = logger;
            }
    

    Import and export now match again. For more information about MEF attributes, see Attributed Programming Model Overview.

Instances of parts created in an MVC app exist in one of two scopes: the request scope or the application scope. By default, part instances that are created during a web request are in a request scope. Instances of parts that are in the same request are shared, so if more than one part imports a given part, all importers receive a reference to the same instance. Each web request has its own scope, so parts created in one request are never used to fill imports in another request.

When a request ends, its associated scope is destroyed and any parts created for it are destroyed. Parts that implement an IDisposable object are disposed. This ensures that sensitive resources, such as database connections, are properly closed.

Sometimes, you might not want to create a part instance for each request (for example, when you implement an app-wide cache). In these cases, you can force a part to be created in the application scope by applying the SharedAttribute attribute. Parts in the application scope are always shared by all requests in the app. A part in the application scope may depend on other part in the application scope only for its imports. Parts in the application scope must be careful to be thread-safe.

You can override these defaults for sharing by using MEF attributes, in the same way that import and export attributes were used in the previous section. For more information about MEF attributes, see Attributed Programming Model Overview.

You can apply action filter attributes to controllers and actions to change the way actions are executed. Although action filter attributes are not created by the composition provider, they can be provided with parts by using the Import attribute.

To provide an action filter

  • Use the Import attribute, as in this example:

public class SaveChangesAttribute : ActionFilterAttribute
{
    [Import]
    public IDbContext DbContext { get; set; }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Exception == null)
            DbContext.SaveChanges();
    }
}
Show:
© 2014 Microsoft