Anelook
Anelook

Reputation: 1277

ASP.NET MVC 4.0 Controllers and MEF, how to bring these two together?

I'm trying to create ASP.NET MVC module by using MEF. While I have no problems so far by using MEF without MVC, when it comes to exporting Controllers I have some difficulties.

I used this approach as example http://kennytordeur.blogspot.de/2012/08/mef-in-aspnet-mvc-4-and-webapi.html I made it more complex by introducing an external dll, which contained a controller. But if I follow the idea of Kenny, then I need to have a common interface (like IMyTest in his example), however, as I plan to have a number of controllers, it would mean that I will need too many interfaces. And in the end, it looks like I reuse inner methods of controllers, instead of whole controllers.

I found a question here How to integrate MEF with ASP.NET MVC 4 and ASP.NET Web API, which contained some code examples, where I see the similar picture - _contactRepository of an interface IContactRepository is imported and then reused inside a view.

That is why my question is, is it normal to export the whole controller, without using interfaces? And how to do so?

I found the connection between MEF and ASP.NET quite confusing, at first it seams that there are a number of examples in the Internet, but when I look deeper, most of them are outdated and not practical or too primitive to see how it can be applied to bigger projects.

Thanks!

Upvotes: 7

Views: 6014

Answers (1)

Morten Mertner
Morten Mertner

Reputation: 9474

I've used MefContrib along with MEF in MVC 4, and am using the following to wire everything up. You need to invoke the Configure method from Application_Start in Global.asax so that everything is ready when MVC needs to process a request.

using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MefContrib.Hosting.Conventions;
using MefContrib.Web.Mvc;

[assembly: PreApplicationStartMethod( typeof(Core.Web.Initialization.DependencyInjection.RegisterDependencyResolver), "RegisterHttpModule" )]

namespace Core.Web.Initialization.DependencyInjection
{
    public class RegisterDependencyResolver
    {
        public static void RegisterHttpModule()
        {
            // Register the CompositionContainerLifetimeHttpModule HttpModule.
            // This makes sure everything is cleaned up correctly after each request.
            CompositionContainerLifetimeHttpModule.Register();      
        }

        public void Configure()
        {
            // Create MEF catalog based on the contents of ~/bin.
            //
            // Note that any class in the referenced assemblies implementing in "IController"
            // is automatically exported to MEF. There is no need for explicit [Export] attributes
            // on ASP.NET MVC controllers. When implementing multiple constructors ensure that
            // there is one constructor marked with the [ImportingConstructor] attribute.
            var catalog = new AggregateCatalog(
                new DirectoryCatalog( "bin" ),
                new ConventionCatalog( new MvcApplicationRegistry() ) );

            // Tell MVC3 to use MEF as its dependency resolver.
            var dependencyResolver = new CompositionDependencyResolver( catalog );
            DependencyResolver.SetResolver( dependencyResolver );

            // Tell MVC3 to resolve dependencies in controllers
            ControllerBuilder.Current.SetControllerFactory( new DefaultControllerFactory( new CompositionControllerActivator( dependencyResolver ) ) );

            // Tell MVC3 to resolve dependencies in filters
            FilterProviders.Providers.Remove( FilterProviders.Providers.Single( f => f is FilterAttributeFilterProvider ) );
            FilterProviders.Providers.Add( new CompositionFilterAttributeFilterProvider( dependencyResolver ) );

            // Tell MVC3 to resolve dependencies in model validators
            ModelValidatorProviders.Providers.Remove( ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single() );
            ModelValidatorProviders.Providers.Add( new CompositionDataAnnotationsModelValidatorProvider( dependencyResolver ) );

            // Tell MVC3 to resolve model binders through MEF. Model binders must be decorated with [ModelBinderExport].
            ModelBinderProviders.BinderProviders.Add( new CompositionModelBinderProvider( dependencyResolver ) );
        }
    }
}

Additionally, you need to export your controllers to MVC. Here's an example of how I do that:

[Export]
[PartCreationPolicy( CreationPolicy.NonShared )]
public partial class HomeController : ControllerCore
{
    [ImportingConstructor]
    public HomeController( DataContext context, ILogFactory logFactory, ServiceFactory serviceFactory ) : base( context, logFactory, serviceFactory )
    {
    }

    public virtual ActionResult Index()
    {
        return View();
    }
}

Hope this helps!

Upvotes: 6

Related Questions