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

1

7

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!

Orvalorvan answered 10/7, 2013 at 19:23 Comment(0)
B
6

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!

Bancroft answered 10/7, 2013 at 21:43 Comment(2)
Morten, thank you for your answer! do I understand correctly, that in your main solution you use HomeController just like any other controller? Or do you need to declare it somewhere in the main application? And what does the class ControllerCore?Orvalorvan
ControllerCore is just a base controller - you can see the constructor invokes a base class, where the parameters are used/stored, but you could just use them directly in the HomeController without having a base class. The configuration code wires up MVC to use MEF when it creates controllers, so there is no extra code needed anywhere (except the call to the Configure method in Application_Start, as mention in the answer).Bancroft

© 2022 - 2024 — McMap. All rights reserved.