MEF2 how to get metadata from CompositionHost export with convention based imports

1.7k views Asked by At

This is my first SO question so please bear with me...

I am trying to load components with MEF2 using the ConventionBuilder class. Everything works as excpected until I need to access metadata that is available as attributes on a imported type. Let's assume I have the following class:

[RuntimeCheckAttribute("MyString1", "MyString2", MyEnum.Value1)]
class ImportedClass : IRuntimeCheck
{...}

Now I could have a ConventionBuilder instance defining a convention for instances of 'IRunTimeCheck':

ConventionBuilder conventions = new ConventionBuilder();
conventions.ForTypesDerivedFrom<IRuntimeCheck>()
           .Export(exp => exp.AsContractType<IRuntimeCheck>()).Shared();

I would then make use of a 'CompositionHost' instance that has been configured to inspect a list of assemblies. A call to

var runtimeChecks = container.GetExports<IRuntimeCheck>();

will then create instances of all exported 'IRuntimeCheck' types.

My question now is how to access the metadata on the IRunTimeCheck-types during the export process. With MEF1 I could make use of the ImportMany / Lazy mechanism. Until now I have not found a good way to rebuild this behaviour with MEF2 as all the Export-overloads on 'CompositionHost' do not allow me to access the metadata attributes.

I have managed to add the metadata on the ConventionBuilder level by using AddPartMetaData:

conventions.ForTypesDerivedFrom<IRuntimeCheck>()
           .AddPartMetadata("securityRuntimeMetadata", AddRuntimeCheckMetadata)
           .Export(exp => exp.AsContractType<IRuntimeCheck>()).Shared();

private object AddRuntimeCheckMetadata(Type arg)
{
    RuntimeCheckAttribute metadata = (arg.GetCustomAttributes<RuntimeCheckAttribute>(false) as  
                                            RuntimeCheckAttribute[]).FirstOrDefault();
    if (metadata == null)
    {
        throw new InvalidOperationException("errorMessage");
    }
    return metadata;
}

When I debug the MEF2 code I can see that the metadata Information is added at the convention builder level. But I could not figure out how to export this Information again. I found a couple of posts that try to make use of the ExportFactory. But most of them are working with non shared exports which is not my goal.

1

There are 1 answers

0
Andreas On

As I wrote as comment I had a similar problem. After some playing around and code step-into I got the necessary meta data without instantiating the type.

This is my ConventionBuilder config:

var cb = new ConventionBuilder();
cb.ForTypesDerivedFrom<IHttpController>()
            .AddPartMetadata(MetadataApiControllerName, t => t.FullName)
            .Export(ex => ex.AddMetadata(MetadataApiControllerName, t => t.FullName))
            .ExportInterfaces();

cb.ForTypesMatching(t => t.BaseType != null && (
                    (t.BaseType.Name.Equals(MetadataControllerName) && !t.BaseType.Name.StartsWith("T4MVC"))
                    || t.BaseType.Name.Equals(MetadataExtentionControllerName)
                    ))
                .AddPartMetadata(MetadataControllerName, t => t.FullName)
                .Export(ex => ex.AddMetadata(MetadataControllerName, t => t.FullName))
                .ExportInterfaces();

I'm working on a MVC / Web Api project and need only some meta information of some controllers. To get them I use this Export:

var controllerExport = _compositionContainer.Container.Value.GetExports<ExportFactory<IController, IDictionary<String, Object>>>()
                    .FirstOrDefault(
                        part => part.Metadata != null &&
                                part.Metadata.ContainsKey(DefaultContainerConfiguration.MetadataControllerName) &&
                                part.Metadata.Any(v => v.Value.ToString()
                                                .EndsWith(controllerName + ControllerNameByConvention, true,
                                                CultureInfo.InvariantCulture)));

The ExportFactory object provides the requested Metadata Dictionary (IDictionary<String, Object>).