How does one integrate Managed Extensibility Framework (MEF) with ASP.NET MVC 4 and ASP.NET Web API in the same project?
Consider an example application, with an MVC controller HomeController
and a Web API controller ContactController
. Both have a property of type IContactRepository
, which they rely on MEF to resolve. The problem is how to plug MEF into MVC and Web API, so that instances are created via MEF.
HomeController:
/// <summary> /// Home controller. Instruct MEF to create one instance of this class per importer, /// since this is what MVC expects. /// </summary> [Export] [PartCreationPolicy(CreationPolicy.NonShared)] public class HomeController : Controller { [Import] private IContactRepository _contactRepository = null; public ActionResult Index() { return View(_contactRepository.GetAllContacts()); } }
ContactController:
/// <summary> /// Contact API controller. Instruct MEF to create one instance of this class per importer, /// since this is what Web API expects. /// </summary> [Export] [PartCreationPolicy(CreationPolicy.NonShared)] public class ContactController : ApiController { [Import] private IContactRepository _contactRepo = null; public Contact[] Get() { return _contactRepo.GetAllContacts(); } }
IContactRepository and ContactRepository:
public interface IContactRepository { Contact[] GetAllContacts(); } [Export(typeof(IContactRepository))] public class ContactRepository : IContactRepository { public Contact[] GetAllContacts() { return new Contact[] { new Contact { Id = 1, Name = "Glenn Beck"}, new Contact { Id = 2, Name = "Bill O'Riley"} }; } }
Contact:
public class Contact { public int Id { get; set; } public string Name { get; set; } }
Asp.Net MVC is used to create web applications that returns both views and data but Asp.Net Web API is used to create full blown HTTP services with easy and simple way that returns only data not view. 2.
You just need to make sure that you get your URLs right, so WebApi calls your MVC controller via it's properly qualified route. To test this, write a simple MVC action which returns some Json data and call it in the browser. If you manage to craft the URL correctly you will see the data displayed in the browser.
Before I illustrate how an ASP.NET MVC controller can be used as an API or a service, let's recap a few things: Web API controller implements actions that handle GET, POST, PUT and DELETE verbs. Web API framework automatically maps the incoming request to an action based on the incoming requests' HTTP verb.
The solution is to implement System.Web.Mvc.IDependencyResolver and System.Web.Http.Dependencies.IDependencyResolver and register your implementation with ASP.NET MVC and ASP.NET Web API respectively, in your Application_Start
method.
In this example we'll create a class MefConfig
, which implements a method RegisterMef
that gets called from Application_Start
in order to install our dependency resolver. The class MefDependencyResolver
implements both System.Web.Mvc.IDependencyResolver
and System.Web.Http.Dependencies.IDependencyResolver
and, as such, handles dependency resolution duties for both MVC and Web API.
Application_Start, Put This in Your Global.asax.cs:
public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { [...] MefConfig.RegisterMef(); } }
MefDependencyResolver and MefConfig:
/// <summary> /// Resolve dependencies for MVC / Web API using MEF. /// </summary> public class MefDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver, System.Web.Mvc.IDependencyResolver { private readonly CompositionContainer _container; public MefDependencyResolver(CompositionContainer container) { _container = container; } public IDependencyScope BeginScope() { return this; } /// <summary> /// Called to request a service implementation. /// /// Here we call upon MEF to instantiate implementations of dependencies. /// </summary> /// <param name="serviceType">Type of service requested.</param> /// <returns>Service implementation or null.</returns> public object GetService(Type serviceType) { if (serviceType == null) throw new ArgumentNullException("serviceType"); var name = AttributedModelServices.GetContractName(serviceType); var export = _container.GetExportedValueOrDefault<object>(name); return export; } /// <summary> /// Called to request service implementations. /// /// Here we call upon MEF to instantiate implementations of dependencies. /// </summary> /// <param name="serviceType">Type of service requested.</param> /// <returns>Service implementations.</returns> public IEnumerable<object> GetServices(Type serviceType) { if (serviceType == null) throw new ArgumentNullException("serviceType"); var exports = _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType)); return exports; } public void Dispose() { } } public static class MefConfig { public static void RegisterMef() { var asmCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(asmCatalog); var resolver = new MefDependencyResolver(container); // Install MEF dependency resolver for MVC DependencyResolver.SetResolver(resolver); // Install MEF dependency resolver for Web API System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = resolver; } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With