问题
After much digging about I figured it's possible to use MEF for DI in MVC4, below SO link gives a couple of examples:
How to integrate MEF with ASP.NET MVC 4 and ASP.NET Web API
They work fine, but I'm wondering how to eliminate the need of explicitly "Import" and "Export" the obvious like your controllers in the MVC 4 app?
There are some suggestions on the web, some top programming minds' blogs. But I had little success in replicating their success stories. Just to name a couple:
http://mef.codeplex.com/wikipage?title=Standalone%20Web%20API%20dependency%20resolver%20using%20Microsoft.Composition&referringTitle=Documentation
http://blog.longle.net/2013/05/17/generically-implementing-the-unit-of-work-repository-pattern-with-entity-framework-in-mvc-simplifying-entity-graphs-part-2-mvc-4-di-ioc-with-mef-attributeless-conventions/
Any suggestions please?
回答1:
The version that ships with .NET 4.0 has no built in way to do this. I think MEF 2 ships with 4.5 and it has some more options including naming conventions. There is probably a version you can download and use with .NET 4.0 somewhere on NuGet.
Microsofts continuous development and pre-releases of their open source libraries is great, but its sometimes quite hard to work out what features are available in each release and what version has made it into which framework. I can't really find a definitive answer...
回答2:
Ok, I have a solution now.
The MEFcontrib offers good support for the convention based model. So simply NuGet it(install-package mefcontrib) to your mvc 4 project.
Once you have the mefcontrib binaries, you just need to register the conventions first and then harness it by adding the convention catalogue. Below snippet shows how:
Convention registration:
public class InitPartsConvention : PartRegistry
{
public InitPartsConvention()
{
Scan(x => x.Assembly(Assembly.GetExecutingAssembly()));
Part()
.ForTypesAssignableFrom<IHttpController>()
.MakeNonShared()
.Export()
.Imports(x =>
{
x.Import().Members(
m => new[] {
m.GetConstructors()
.FirstOrDefault(
c => c.GetCustomAttributes(typeof(ImportingConstructorAttribute), false).Length > 0)
?? m.GetGreediestConstructor()
});
x.Import().Members(
m => m.GetMembers(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic)
.Where(
mbr => mbr.GetCustomAttributes(typeof(ImportAttribute), false).Length > 0).ToArray()
);
});
Part()
.ForTypesAssignableFrom<IController>()
.MakeNonShared()
.Export()
.Imports(x =>
{
x.Import().Members(
m => new[] {
m.GetConstructors()
.FirstOrDefault(
c => c.GetCustomAttributes(typeof(ImportingConstructorAttribute), false).Length > 0)
?? m.GetGreediestConstructor()
});
x.Import().Members(
m => m.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(
mbr => mbr.GetCustomAttributes(typeof(ImportAttribute), false).Length > 0).ToArray()
);
});
}
}
This registers your api controllers and mvc controller so that they can be MEFified. It does not cover the AsyncController however.
MEF MVC bootstrapper
public static class MefBootstrapper
{
public static void RegisterMef()
{
var container = GetContainer();
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;
}
private static CompositionContainer GetContainer()
{
var path = HostingEnvironment.MapPath("~/bin");
if (path == null) throw new Exception("Unable to find the path");
var catelog = new AggregateCatalog(
new DirectoryCatalog(path),
new ConventionCatalog(new InitPartsConvention())); // this adds the convention to MEF
return new CompositionContainer(catelog);
}
}
That's it, job done! Enjoy dynamic DI in your MVC 4 apps.
来源:https://stackoverflow.com/questions/16626637/so-weve-got-mef-working-with-mvc4-how-about-the-convention-based-model