I'm trying to use MEF in my asp.net mvc 3 application, but I could not realise the injection. Here is the code:
I have an interfaces class library which has:
namespace Namespace.Interfaces
{
public interface IMessenger
{
string GetMessage();
}
}
And in another class library I have the class inherits from IMessenger:
namespace Namespace.Message
{
[Export(typeof(IMessenger))]
public class Messenger : IMessenger
{
public Messenger()
{
}
public string GetMessage()
{
return "Mef Test!";
}
}
}
I have a "Parts" directory in my application and I'm copying the dll of class library which contains class named "Messenger".
In global.asax I have:
private static CompositionContainer _container;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
DirectoryCatalog catalog = new DirectoryCatalog(Server.MapPath("Plugins"), "*.dll");
_container = new CompositionContainer(catalog);
_container.ComposeParts();
DependencyResolver.SetResolver(new MefDependencySolver(_container));
}
Here is the MefDependencyResolver class:
public class MefDependencySolver : IDependencyResolver
{
public MefDependencySolver(CompositionContainer compositionContainer)
{
this.compositionContainer = compositionContainer;
}
private CompositionContainer compositionContainer;
public object GetService(Type serviceType)
{
string name = AttributedModelServices.GetContractName(serviceType);
return compositionContainer.GetExportedValueOrDefault<object>(name);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.compositionContainer.GetExportedValues<object>(serviceType.FullName);
}
}
And at last I'm trying to use it in my controller like that:
public class HomeController : Controller
{
[ImportAttribute]
public IMessenger _messenger { get; set; }
public HomeController()
{
}
public ActionResult Index()
{
ViewBag.Message = _messenger.GetMessage();
return View();
}
}
But it doesn't create the _messenger object. I'm getting object reference not set to an instance of an object. What am I doing wrong?
Thanks in advance,
First of all you should rewrite your GetServices
method that way :
public IEnumerable<object> GetServices(Type type)
{
string name = AttributedModelServices.GetContractName(type);
try
{
return container.GetExportedValues<object>(name);
}
catch
{
return new object[] {};
}
}
What's important is to return an empty list if the service cannot be resolved.
The second thing is to favor injection by constructor and not by property. The dependency IMessenger is needed so it's better to ask for it by constructor. You can revrite it like this :
public HomeController : Controller
{
private readonly IMessenger _messenger;
[ImportingConstructor]
public HomeController(IMessenger messenger)
{
_messenger = messenger;
}
// other actions
}
I think that the problem comes from this line _container.ComposeParts();
. I don't think you should call it. MEF will be doing it for you.