Reputation: 7269
I'm trying to implement the the Microsoft Extensibility Framework (MEF) into a sample MVC-based web app. I'm using the SimpleCalculator example solution on the MEF Overview page. My goal is an application that can dynamically load a DLL extension from another project in order to extend the capabilities of the Model, essentially I want the MVC-Application to be a framework for other extensions to plug-into. First my setup:
Project 1 (MVC-Application, MEF Component Host):
I decorate the elements in my Model as follows:
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace ExpressionParserPOC.Models
{
public class ExpressionModel
{
private CompositionContainer _container;
[ImportMany]
IEnumerable<Lazy<IExtensions,IExtensionName>> extensions { get; set; }
public ExpressionModel()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog("C:\\local_visual_studio\\ExpressionParserPOC\\ExpressionParserPOC\\Extensions"));
//Create the CompositionContainer with the parts in the catalog
_container = new CompositionContainer(catalog);
_container.ComposeParts(_container);
//TEST: Can we access the extensions?
if (extensions != null)//<--NULL WHEN CONSTRUCTOR IS CALLED WHY? Expected GetMatrix() Function from DLL to be exposed
{
foreach (Lazy<IExtensions, IExtensionName> i in extensions)
{
Lazy<IExtensions, IExtensionName> foo = i;
}
}
}
}
public interface IExtensions
{
double[][] GetMatrix(string matrix);
}
public interface IExtensionName
{
Char Symbol { get; }
}
}
To test right now, I'm just calling the constructor for the Model from the Controller:
namespace ExpressionParserPOC.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Enter an Expression for Octave to evaluate";
//Instantiate an ExpressionModel composed of extensible parts
var model = new ExpressionModel();
return View(model);
}
}
}
Project 2 (DLL Project, MEF Component):
//PROJECT BUILD OUTPUTS TO THE EXTENSIONS DIRECTORY IN PROJECT 1 ABOVE
using System.ComponentModel.Composition;
namespace MyExtensions
{
//Project 1 already added as a reference
[Export(typeof(ExpressionParserPOC.Models.IExtensions))]
[ExportMetadata("Symbol", 'o')]
public class Octave : MyExtensions.IExtensions
{
//Other class properties, constructors, functions, etc.
#region FUNCTIONS
public double[][] GetMatrix(string matrix)
{
double[][] mat = new double[][];
//Do Stuff
return mat;
}
#endregion
}
public interface IExtensions : ExpressionParserPOC.Models.IExtensions
{
}
}
Problem is that the the extensions List in the host MVC application project never gets filled when I call the Model constructor from the Controller in that same project. I'm new to MEF development and am not sure what I'm doing wrong, is there something extra I need to consider since I'm working with an MVC application? Why won't the Project 1 extensions list get filled? Are my interface definitions wrong? The sample calculator application is a simple command line project and that seems to work fine, the only difference I see is that the external DLL project is in the same solution space, whereas with my example the solution spaces are independent.
Upvotes: 2
Views: 345
Reputation: 14116
A trivial mistake you have there in the ExpressionModel
constructor. You are composing the container itself :)
_container.ComposeParts(_container);
The problem should be apparent instantly, because if the composition of the ExpressionModel
actually ever happened, even if no extensions were discovered, the extensions
property would be initialized with 0 items, but it wouldn't be null
.
You need to compose the current model instance like this:
_container.ComposeParts(this);
Everything else seems to be alright and should be working fine after this correction.
Upvotes: 1