How to create new objects from MEF imports - c#

I am a little confused by MEF, I thought I had begun to understand it but it appears I am not quite there.
So, I have a list of test steps in XML that I want to read in. The idea is that the main application doesn't know anything about the types at run time.
<TestSteps>
<TestRunner xsi:type="SimulateDc" Measurement="54"/>
<TestRunner xsi:type="MeasureDc" Output="1"/>
</TestSteps>
So I have a base type with a static "results" class that allows me to save information to pass between steps (The Output attribute in the XML above). The test handlers here are exported by MEF, I read them in at runtime and then get the Type to pass into the XML serializer to create a list of handlers. This all works and I get a list of test runners. I have a DataTemplate export for each type here so when I use a Content Control it knows how to draw itself. All all seems fine, however I think I have gone wrong in my thought process.
One issue is that I now want to tie the imported handlers to some hardware. the hardware handling routines are intended to be handled by yet more MEF imports
So with an interface like this:
public interface IMeasureHW
{
double Measure();
}
Then using this:
[Export("MeasureDc", typeof(IMeasureHW))]
public class MeasureDcHW : IMeasureHW
{
public double Measure()
{
return 54.0;
}
}
Then in one of my test handlers I have done this:
[Import("MeasureDc", typeof(IMeasureHW))]
IMeasureHW hardware { get; set; }
My importing is carried out like this:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog("."));
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
_container = new CompositionContainer(catalog);
_container.ComposeParts(this);
MainWindow.Show();
}
However, I am guessing the XML serialization above and using the Type information as I do would definitely mean the import would be null so implying my thought patterns for the design are in error.
I did manage to get it to work by exporting the CompositionContainer and then after loading the XML I am able to do this:
foreach (TestRunnerBase t in testSteps)
{
_container.SatisfyImportsOnce(t);
}
But that feels a bit wrong to me, as the initial list of imported test steps isn't being used for anything apart from getting the type. So I was thinking that I should be exporting the data as MEF parts and then independently exporting the handlers, then somehow when I read in my list of data from the XML I ask for a handler from the list? If that makes sense?
I couldn't work out how you would tie them together in this way as the MEF composition is all handled in my App.xaml.cs and the test steps are in a view model elsewhere. I was thinking something along the lines of using metadata to tie data to a handler, and then finding the corresponding handler in the imported list. Perhaps I should carry out an initial parse to build a dictionary to speed up lookups?
Is this more the way it should be done? Any help appreciated, I am already quite light in the hair department so I can't afford to lose more

Please correct me if I'm wrong - It seems as though you could achieve your goal by chaining imports: innermost being your TestRunner collection, then the hardware classes, then finally the content control.
In the example below these are Class2 : MySubInterface, Class1 : MyInterface, and Program respectively:
/////inner
using MyHostingNamespace;
namespace ClassLibrary1
{
[Export("class2", typeof(MySubInterface))]
class Class2 : MySubInterface
{
public string MyProperty { get; set; }
public Class2()
{
MyProperty = "Class2";
}
}
}
////middle
using MyHostingNamespace;
namespace ClassLibrary1
{
[Export("class1", typeof(MyInterface))]
public class Class1 : MyInterface
{
[Import("class2", AllowDefault=true)]
MySubInterface myClass2;
public string MyProperty {get;set;}
public Class1()
{
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
CompositionContainer _container = new CompositionContainer(catalog);
_container.ComposeParts(this);
MyProperty = myClass2.MyProperty;
}
}
}
////outer
namespace MyHostingNamespace
{
class Program
{
[Import("class1")]
public MyInterface class1;
public Program()
{
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
catalog.Catalogs.Add(new DirectoryCatalog("."));
CompositionContainer _container = new CompositionContainer(catalog);
_container.ComposeParts(this);
}
static void Main(string[] args)
{
Program p = new Program();
Console.WriteLine(p.class1.MyProperty);
}
}
public interface MyInterface
{
string MyProperty { get; set; }
}
public interface MySubInterface
{
string MyProperty { get; set; }
}
}

Related

Dynamic property interception

I have classes with properties implemented in dll (I can not change implementation because i do not have huge source code). I can not replace using of property Name with inherited class because project have thousands lines of code where it used(Ctrl+h does not help). Somebody told that my problem can be solved by Dynamic property interception across Castle and Unity. But i cannot find any workable small examples. Can you show how to implement it? I read that Castle dynamic proxy intercepts only virtual methods. Is it possible to intercepts non virtual methods with interface?
namespace DynamicInterception
{
// Placed int first dll
public class Cargo
{
public string Name { get; set; }
}
//Placed in second dll
public class Wagon
{
public Cargo Cargo { get; set; }
}
class Program
{
static void Main(string[] args)
{
Wagon wagon = new Wagon();
wagon.Cargo = new Cargo() { Name = "Test" };
}
}
}
Yes, with Castle Dynamic Proxy you can intercept non-virtual members of a class if the member is part of an interface. Look at the documentation (specifically the section on IInterceptor) and if you're having problems, start a new question with some sample code showing the issue you're having.

Compose Imports using run-time defined Contract Name

I have an MEF Export like below:
public interface IMyInterface { }
public interface IInterfaceData
{
string[] Data { get; }
}
[Export("MyContractName", typeof(IMyInterface))]
[ExportMetadata("Data", "SomeData", IsMultiple = true)]
public class MyInterfaceClass : IMyInterface { }
Which I then Import using:
public class MyClass {
[ImportMany("MyContractName", typeof(IMyInterface))]
private IEnumerable<Lazy<IMyInterface, IInterfaceData>> _operations;
private CompositionContainer _container;
private void Compose() {
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
_container = new CompositionContainer(catalog);
_container.ComposeParts(this);
}
}
This works fine. However, I would like to be able to Compose my Imports at Run Time using a contract name based on the currently executing business logic. In other words, I would like to be able import a variable contract name. I can get around this by doing this:
private void Compose() {
var contractName = "MyContractName"; // note this would be determined at run-time
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
_container = new CompositionContainer(catalog);
var foundExports = _container.GetExports<IMyInterface, IInterfaceData>(contractName);
_operations = foundExports; // set manually
}
I am more than happy to do to this*. However, there is now no reason for the [ImportMany] attribute and I can no longer use ComposeParts(). I would like to keep things consistent throughout my project (for my sake, and my team's) and would like to be able to rely on MEF Attributes, Compose()/ComposeParts() or both.
Is there some other way to define the Import attributes, such that calling _container.Compose() would take into account a run-time defined contract name? Perhaps the Exports need to be changed or there is something else in the MEF framework that is available to me (attribute wise)?
*I am not sure if this is even "correct". even though it does work. It just feels sloppy if I'm trying to keep all things somewhat consistent.
This can be done by directly using a CompositionBatch on your container.
var batch = new CompositionBatch();
// Add the export to the batch via method or object referebce
batch.AddExport(new Export(name, partFactory));
batch.AddExport(new Export(part.Name, () => part));
// Compose into your CompositionContainer
_container.Compose(batch);
private MyClass PartFactory()
{
// TODO: create the part to export..
}
Note that for the container object, it is possible to export the container itself using CompositionOptions.ExportCompositionService during construction, thus allowing
[Import] CompositionContainer _container;

Why SatisfyImportsOnce method doesn't work with the object parameter?

I have been following this MSDN example about the CompositionContainer class (System.ComponentModel.CompositionHosting):
[Export]
class MyAddin
{
public String myData { get { return "The data!"; } }
}
class MyProgram
{
[Import]
public MyAddin myAddin { get; set; }
}
class Program
{
static void Main(string[] args)
{
AggregateCatalog catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(MyAddin).Assembly));
CompositionContainer _container = new CompositionContainer(catalog);
MyProgram myProgram = new MyProgram();
_container.SatisfyImportsOnce(myProgram);
Console.WriteLine(myProgram.myAddin.myData);
Console.ReadLine();
_container.Dispose();
}
}
But when I try to compile it, this error message is generated:
Error 2 The best overloaded method match for
'System.ComponentModel.Composition.Hosting.CompositionContainer.SatisfyImportsOnce(System.ComponentModel.Composition.Primitives.ComposablePart)'
has some invalid
arguments X:\Dev\S-L\CSharp\EtceteraSolution\CompositionContainer_Demo\CompositionContainer_Main.cs 15 13 CompositionContainer_Demo
Sample source: http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.hosting.compositioncontainer%28v=vs.110%29.aspx
You are missing extension method that can do it. You just need to add correct using on top of your program. I guess the example doesn't show the necessary usings.
The method you're looking for is: public static ComposablePart SatisfyImportsOnce(this ICompositionService compositionService, object attributedPart);
Add using System.ComponentModel.Composition on your program, and the extension method should work fine.
Alternatively, it's also possible to call extensionmethod like this:
AttributedModelServices.SatisfyImportsOnce(_container, myProgram);
Note, it's in .NET framework >= 4.0.

How can I handle recursive composition in MEF?

Consider the following code sample that uses MEF to create an object of type Importer that imports an object of type ImporterExporter which in turn imports an object of type Exporter, i.e. Importer -> ImporterExporter -> Exporter. The catalog is managed by a CompositionUtility (obviously simplified for this example).
I know that MEF will resolve imports recursively on imported parts. However, because I want to have the option to instantiate each of these classes independetly, every class with imports also composes itself in its constructor to resolve those imports.
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
namespace MefRecursionSample
{
class Program
{
static void Main(string[] args)
{
// var importerExporter = new ImporterExporter(); // include this and composition will work
var importer = new Importer();
Console.Write(importer.ImporterExporter.Exporter.Value); // should print 7
Console.ReadKey();
}
}
class CompositionUtility
{
static CompositionUtility()
{
var executingAssembly = Assembly.GetExecutingAssembly();
var assemblyCatalog = new AssemblyCatalog(executingAssembly);
_compositionContainer = new CompositionContainer(assemblyCatalog);
}
private static CompositionContainer _compositionContainer;
private static bool _isComposing;
public static void Compose(object part)
{
_compositionContainer.ComposeParts(part);
}
}
class Importer
{
public Importer()
{
CompositionUtility.Compose(this);
}
[Import]
public ImporterExporter ImporterExporter { get; set; }
}
[Export]
class ImporterExporter
{
public ImporterExporter()
{
CompositionUtility.Compose(this);
}
[Import]
public Exporter Exporter { get; set; }
}
[Export]
class Exporter
{
public int Value { get { return 7; } }
}
}
Running the code as is leads to a composition error "The ComposablePart of type MefRecursionSample.Importer' cannot be recomposed....", obviously because I am trying to explictly compose something that MEF also wants to compose.
What surprised me, was the fact that when I included the first line of the Main method, i.e. create an object of type ImporterExporter without MEF, this "double-composition" no longer caused an exception. Why is that?
Also, how could I make it work such that I could instantiate each of these indepennetly, yet also make them compose themselves when chained as in the sample. I figured I would introduce a boolean flag _compositionInProgress on the CompositionUtility and immediately return from Compose() when the flag is set to avoid the recursive composition. Is there a better way?
The flag I considered setting in the CompositionUtility's Compose method does not work, because there can be cases where the string of automatic imports is interrupted. For instance, in the question's example if Exporter instantiated a class in its constructor using new and this class would want to compose itself. Under the original solution, that class' call to Ccompose would return immediately, leaving the class uncomposed.
Because I want classes to compose themselves (thus making it unneccessary for their users to even know about MEF), the only solution was to establish the rule that classes with an [Export] attribute must not call Compose(this). Because they will be composed automatically by MEF when being imported, this would result in "double composition" and thus throw an exception.
If it is a requirement that classes marked with [Export] have to instantiated independently via new instead of nly imported via MEF, they have to have an addional constructor with a boolean flag which when set well trigger composition of that class. The default behavior, however, has to be no composition in order to avoid the aforementioned "double composition".
why not simply do this?
class Program
{
private static CompositionContainer _compositionContainer;
static void Main(string[] args)
{
//compose the container just one time in your app
var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
_compositionContainer = new CompositionContainer(assemblyCatalog);
var importer = _compositionContainer.GetExportedValue<Importer>();
Console.Write(importer.ImporterExporter.Exporter.Value); // should print 7
Console.ReadKey();
}
}
[Export]
class Importer
{
[ImportingConstructor]
public Importer(ImporterExporter imex)
{
this.ImporterExporter = imex;
}
public ImporterExporter ImporterExporter { get; private set; }
}
[Export]
class ImporterExporter
{
[ImportingConstructor]
public ImporterExporter(Exporter exporter)
{
this.Exporter = exporter;
}
public Exporter Exporter { get; private set; }
}
[Export]
class Exporter
{
public int Value { get { return 7; } }
}
What you really want to do (I think) is calling container.SatisfyImportsOnce() on an object and not ComposeParts .
ComposeParts adds all exports tree to the catalog while SatisfyImportsOnce each object is to itself , composing parts and thats it , no registeration of recursive exports , so you can call constructor or use importing constructor , you can have both.
James.

Satisfying imports for an existing object using MEF

Given an arbitrary already existing object which is attributed with [Import] tags, what's the tambourine dance I have to do in order to get MEF to fill in the imports?
Much of the blog documentation seems to be built against preview versions of MEF and don't work anymore - I'm using the released one that's part of .NET 4.0 (or alternatively, MEF 2.0 Preview 3).
AggregateCatalog _catalog;
CompositionContainer _container;
public void Composify(object existingObjectWithImportTags)
{
lock(_container) {
var batch = new CompositionBatch();
// What do I do now?!?!
}
}
MEF resolves Imports (through property or constructor injection), along whith their own dependencies, from exported types in the registered assemblies registered in the catalog (including the current assembly).
If you want to create an object directly (using the new keyword), or in case the export wasn't ready at the time of the creation, you can use the container to satisfy the imports of an object, using:
_container.SatisfyImportsOnce(yourObject);
I've put together a little scenario doing just that. here's the code:
public class Demo
{
private readonly CompositionContainer _container;
[Import]
public IInterface Dependency { get; set; }
public Demo(CompositionContainer container)
{
_container = container;
}
public void Test()
{
//no exported value, so the next line would cause an excaption
//var value=_container.GetExportedValue<IInterface>();
var myClass = new MyClass(_container);
//exporting the needed dependency
myClass.Export();
_container.SatisfyImportsOnce(this);
//now you can retrieve the type safely since it's been "exported"
var newValue = _container.GetExportedValue<IInterface>();
}
}
public interface IInterface
{
string Name { get; set; }
}
[Export(typeof(IInterface))]
public class MyClass:IInterface
{
private readonly CompositionContainer _container;
public MyClass()
{
}
public MyClass(CompositionContainer container)
{
_container = container;
}
#region Implementation of IInterface
public string Name { get; set; }
public void Export()
{
_container.ComposeExportedValue<IInterface>(new MyClass());
}
#endregion
}
Now, just use new Tests(new CompositionContainer()).Test(); to start the demo.
Hope this helps :)
_container.ComposeParts(existingObjectWithImportTags);
ComposeParts is an extension method that you are looking for.
It simply creates a CompositionBatch and calls AddPart(AttributedModelServices.CreatePart(attributedObject)) and then calls _container.Compose(batch).

Categories