4

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.

SBeltz
  • 41
  • 3
  • i encountered the same problem creating a MVC ControllerFactory. Did you find any solution yet? – Andreas Aug 14 '14 at 14:52
  • @Andreas no reply until now... I also posted this to the MSDN application developer forum. They couldn't help me either and suggested to post the question in the MEF Forum at the MSDN Silverlight Developer Center. As the most recent post over there dates back to December 2013 I decided to keep my MEF1 implementation for the moment. Please let me know when you find any viable solution. Thanks! – SBeltz Aug 18 '14 at 13:08

1 Answers1

2

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>).

Andreas
  • 2,252
  • 1
  • 19
  • 29