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.
Related
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;
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.
Needs -
To declare shared exports of the same interface. The exports are marked by unique export names so consumers may import a particular flavor of the export.
To inject a common instance of the class into a set of objects but to not share a common instance across sets of objects [This makes me use shared exports using different keys - one set of objects can use a single key to get satisfy their shared import need]
Here is the export class
public interface IMyExport
{
void Display();
}
public class MyExport : IMyExport
{
private Guid _id = Guid.NewGuid();
public void Display()
{
Console.WriteLine("Instance ID = "+_id);
}
}
and here is how I export instances of the class
public static class ExportInitialization
{
[Export("Type A", typeof(IMyExport)),
Export("Type B", typeof(IMyExport))]
public static IMyExport IceCreamExport
{
get
{
return new MyExport();
}
}
}
Consumers may import specific instances in the following manner
[Export]
public class ImporterA
{
private readonly IMyExport _myExport;
[ImportingConstructor]
public ImporterA([Import("Type A")]IMyExport myExport)
{
_myExport = myExport;
}
public void Display()
{
_myExport.Display();
}
}
[Export]
public class ImporterB
{
private readonly IMyExport _myExport;
[ImportingConstructor]
public ImporterB([Import("Type B")]IMyExport myExport)
{
_myExport = myExport;
}
public void Display()
{
_myExport.Display();
}
}
class Program
{
[Import]
public ImporterA ImporterA { get; set; }
[Import]
public ImporterB ImporterB { get; set; }
static void Main(string[] args)
{
new Program().Run();
}
public void Run()
{
var container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
container.ComposeParts(this);
ImporterA.Display();
ImporterB.Display();
Console.ReadKey();
}
}
This used to work fine with .Net 4.0 but when .Net 4.5 is installed - I get the following ouptut
Instance ID = 78bba41a-0c48-44fc-ae69-f0ead96371f9
Instance ID = 78bba41a-0c48-44fc-ae69-f0ead96371f9
Notice that the same instance of the object is returned for both imports. Am I breaking some undocumented rule regarding exporting via static properties?
I found that exporting the specific instances from two distinct static properties ensures that 2 distinct instances are returned.
[Export("Type A", typeof(IMyExport))]
public static IMyExport ExportA
{
get
{
return new MyExport();
}
}
[Export("Type B", typeof(IMyExport))]
public static IMyExport ExportB
{
get
{
return new MyExport();
}
}
This is puzzling since in the unmodified version the static getter was creating a new instance on every get. Not sure if this is the result of some C#/.Net optimization introduced with 4.5 or if this is a MEF issue
This is related to the MEF parts lifetime.
The default for MEF attributes is that components do not say whether they care to get a new instance each time or not.
Meaning that:
Your ExportAttribute does not specify whether exported instances can or should be shared;
Both of the ImportAttributes do not specify whether their import should be shared or not;
The default behavior of MEF is that, if it is not forbidden from sharing instances, it will. Meaning that, according to the documentation, the behavior of .NET 4.5 is the correct one: the instance of MyExport is shared, given that no-one on either side explicitly forbade sharing.
I think that .NET 4.0 had a bug/discrepancy where the static property was called every time, which resulted in what you observed, that is, non shared instances. And you were relying on that bug. I think that the bug finds its origin in a fundamental, framework-wide expectation for properties - it is very unusual to have a static property create a new, semantically distinct, instance for each property call.
I believe you should:
Replace your static property export with a static method export;
Specify the creation policy to non-shared, on either the Export side or the Import side;
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; }
}
}
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).