Cómo integrar MEF con ASP.NET MVC 4 y ASP.NET Web API
asp.net-mvc asp.net-mvc-4 (6)
Este es un enfoque más simple que estoy usando en mi proyecto MVC4.
public static class MefConfig
{
public static CompositionContainer MefContainer = null;
public static void Initialise()
{
AggregateCatalog cat = new AggregateCatalog();
cat.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
MefContainer = new CompositionContainer(cat);
}
}
public class MefFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
MefConfig.MefContainer.ComposeParts(filterContext.Controller);
}
}
En Application_Start ejecute MefConfig.Initialise () y en FilterConfig.RegisterGlobalFilters (filtros GlobalFilterCollection) ponga filters.Add (new Filters.MefFilterAttribute ());
¿Cómo se puede integrar Managed Extensibility Framework (MEF) con ASP.NET MVC 4 y ASP.NET Web API en el mismo proyecto?
Considere una aplicación de ejemplo, con un controlador MVC HomeController
y un controlador de API web ContactController
. Ambos tienen una propiedad de tipo IContactRepository
, que dependen de MEF para resolver. El problema es cómo conectar MEF a MVC y API web, de modo que las instancias se creen a través de 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 y 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"}
};
}
}
Contacto:
public class Contact
{
public int Id { get; set; }
public string Name { get; set; }
}
La respuesta de @ aknuds1 es la mejor que he visto hasta ahora para integrar MEF en DependencyResolver. Pude extenderlo para utilizar la composición basada en la convención en MEF2 con bastante facilidad. La clase MefConfig es todo lo que se necesita para cambiar y luego no mucho.
/// <summary>
/// Responsible for configuring MEF for the application.
/// </summary>
public static class MefConfig
{
/// <summary>
/// Registers MEF conventions and exports.
/// </summary>
public static void RegisterMef()
{
// Register MVC/API conventions
var registrationBuilder = new RegistrationBuilder();
registrationBuilder.ForTypesDerivedFrom<Controller>().SetCreationPolicy(CreationPolicy.NonShared).Export();
registrationBuilder.ForTypesDerivedFrom<ApiController>().SetCreationPolicy(CreationPolicy.NonShared).Export();
var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly(), registrationBuilder);
var aggregateCatalog = new AggregateCatalog(assemblyCatalog);
var container = new CompositionContainer(aggregateCatalog);
var resolver = new MefDependencyResolver(container);
// Install MEF dependency resolver for MVC
DependencyResolver.SetResolver(resolver);
// Install MEF dependency resolver for Web API
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
}
La solución de Mr Kenny Torduer funcionó para mí mientras que la supuesta respuesta correcta no lo hizo (no pude resolver la instancia del controlador aunque todas las partes dependientes están en el catálogo de catego, me dieron un error de "tipo no tiene un constructor predeterminado").
Corrección : ambos enfoques funcionan en realidad, estaba siendo estúpido por un error elemental en el registro de piezas de la convención. Mi sincera disculpa al autor de la respuesta correcta.
La solución es implementar System.Web.Mvc.IDependencyResolver y System.Web.Http.Dependencies.IDependencyResolver y registrar su implementación con ASP.NET MVC y ASP.NET Web API, respectivamente, en su método Application_Start
.
En este ejemplo, crearemos una clase MefConfig
, que implementa un método RegisterMef
que se llama desde Application_Start
para instalar nuestro resolvedor de dependencias. La clase MefDependencyResolver
implementa tanto System.Web.Mvc.IDependencyResolver
como System.Web.Http.Dependencies.IDependencyResolver
y, como tal, maneja los deberes de resolución de dependencia tanto para MVC como para Web API.
Application_Start, Pon esto en tu Global.asax.cs:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
[...]
MefConfig.RegisterMef();
}
}
MefDependencyResolver y 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;
}
}
Puede echar un vistazo a este http://kennytordeur.blogspot.be/2012/08/mef-in-aspnet-mvc-4-and-webapi.html . Explica cómo usar MEF en un proyecto Asp.net MVC 4 / Web Api. También existe un paquete Nuget basado en este código. De esa manera puedes probarlo muy fácil y rápidamente.
Seguí la respuesta de @ akanuds1 pero también tuve que cambiar el ControllerFactory a esto:
public class MefControllerFactory : DefaultControllerFactory
{
private readonly CompositionContainer compositionContainer;
public MefControllerFactory(CompositionContainer compositionContainer)
{
this.compositionContainer = compositionContainer;
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
var export = compositionContainer.GetExports(controllerType, null, null).SingleOrDefault();
IController result;
if (null != export)
{
result = export.Value as IController;
}
else
{
result = base.GetControllerInstance(requestContext, controllerType);
compositionContainer.ComposeParts(result);
}
return result;
}
}
Glogal.asax.cs
protected void Application_Start()
{
...
var container = MefConfig.Register();
ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
}