Comment intégrer MEF avec ASP.NET MVC 4 et ASP.NET API Web
Comment intégrer Cadre De Gestion De L'Extensibilité (MEF) avec ASP.NET MVC 4 et ASP.NET API Web dans le même projet?
prenons un exemple d'application, avec un contrôleur MVC HomeController
et un contrôleur D'API Web ContactController
. Les deux ont une propriété de type IContactRepository
, qu'ils comptent sur le MEF pour résoudre. Le problème est de brancher MEF dans MVC et API Web, de sorte que les instances soient créées 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();
}
}
Icontactreprository and Contactreprository:
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; }
}
6 réponses
la solution est d'implémenter Système.Web.Mvc.IDependencyResolver et Système.Web.Http.Dépendance.IDependencyResolver et enregistrez votre implémentation avec ASP.NET MVC et ASP.NET API Web respectivement, dans votre Application_Start
méthode.
Dans cet exemple, nous allons créer une classe MefConfig
, qui implémente une méthode RegisterMef
qui est appelée à partir de Application_Start
afin d'installer notre résolveur de dépendances. La classe MefDependencyResolver
implémente les deux System.Web.Mvc.IDependencyResolver
et System.Web.Http.Dependencies.IDependencyResolver
et, à ce titre, s'occupe des fonctions de résolution de dépendances pour MVC et API Web.
Application_Start, mettez ceci dans votre 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;
}
}
Vous pouvez prendre un coup d'oeil à ce http://kennytordeur.blogspot.be/2012/08/mef-in-aspnet-mvc-4-and-webapi.html. Il explique comment utiliser le MEF dans un Asp.net MVC 4/Api Web du projet. Il existe aussi Nuget package basé sur ce code. De cette façon, vous pouvez le tester très facilement et rapidement.
@aknuds1 réponse est le meilleur que j'ai vu jusqu'à présent pour l'intégration de la MEF dans le DependencyResolver. J'ai pu l'étendre assez facilement pour utiliser la composition basée sur la convention dans MEF2. La classe MefConfig est tout ce qu'il fallait changer et puis pas de beaucoup.
/// <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 solution de M. Kenny Torduer a fonctionné pour moi alors que la réponse supposée correcte n'a pas fonctionné (je n'ai pas pu résoudre l'instance du contrôleur bien que toutes les parties dépendantes soient dans le catelog, on m'a donné une erreur "type does not have a default constructor")!
Correction: les deux approches fonctionnent en fait, j'étais stupide par une erreur élémentaire dans le registre des parties de convention. Mes sincères excuses à l'auteur de la bonne réponse.
c'est une approche plus simple que j'utilise dans mon projet 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);
}
}
Dans Application_Start exécuter MefConfig.Initialise () et dans FilterConfig.RegisterGlobalFilters (GlobalFilterCollection filters) mettre des filtres.Ajouter (nouveaux filtres.MefFilterAttribute ());
j'ai suivi la réponse de @akanuds1 mais j'ai aussi dû changer le ControllerFactory en ceci:
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));
}