1
votes

I am attempting to build a modular application using MEF.
However, while composing it seems to ignore SetExportedValue(..., ...), resulting in it not finding the values/objects I need.

Here is my (anonymized and simplified) code:

interface IPlugin {  }

class MyClass
{
    [ImportsMany(typeof(IPlugin))]
    public IEnumerable<Lazy<IPlugin>> Plugins;

    public LoadParts()
    {
        var ac = new AggregateCatalog();
        ac.Catalogs.Add(new AssemblyCatalog(typeof(PluginManager).Assembly));

        // imagine adding some DirectoryCatalogs here

        var cc = new CompositionContainer(ac);
        cc.ComposeExportedValue("MyValue", someinstance);
        cc.ComposeParts(this);
    }
}

[Export(typeof(IPlugin))]
class MyPart : IPlugin
{
    [ImportingConstructor]
    public MyPart([Import("MyValue")] sometype arg)
    { }
}

This results in the following error message:

System.ComponentModel.Composition Warning: 1 : The ComposablePartDefinition 'MyNamespace.MyPart' has been rejected. The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

1) No exports were found that match the constraint:

ContractName  MyValue
RequiredTypeIdentity  somenamespace.sometype

Resulting in: Cannot set import 'MyNamespace.MyPart..ctor (Parameter="...", ContractName="...")' on part 'MyNamespace.MyPart'.
Element: MyNamespace.MyPart..ctor (Parameter="...", ContractName="...") --> MyNamespace.MyPart --> DirectoryCatalog (Path="./")

Am I misunderstanding how part constructors work?
How do I get it to accept the constructor parameter?


Edit for claification: someinstance is a specific instance of sometype. I do not want to add a type to the container, but a specific class instance.

1

1 Answers

1
votes

Your ImportingConstructor needs valid contracts too, and not just values.

This is an Example, how my Constructor works:

[ImportingConstructor]
    public MyType([Import] IStatus status, [Import] IProtocoll protocoll) {
    }

As you can see, you need to use Interfaces as Contructor-Parameters.

These interfaces are plain and simple without any required Attributes.

Snippet of IProtocoll

public interface IProtocoll {

    IProtocollStateController ProtocollController { get; set; }

    void WriteProtocoll(string action, string message, bool? result, Guid conditionId);

    void WriteProtocoll(Protocoll protocoll);

    List<Protocoll> GetAllProtocoll();
  }

I suggest you to turn your MyValue in an valid interface. This might be a bit overkill for a simple string but this how MEF works.

Cheers