简体   繁体   中英

Strongly typed metadata in MEF2 (System.Composition)

I'm using the System.Composition namespace from the MEF for web and Windows Store apps NuGet package in a new ASP.NET MVC4 project.

I've read that in MEF2 you no longer use Lazy<IExtension, IExtensionMetadata> , but now you must provide a concrete type for the metadata view (and possibly use ExportFactory<> instead of Lazy<> ?).

However, I can't find any examples of how this should all work - just a few mentions of using a concrete type instead of an interface.

I've tried a few things, but keep getting the following error - " Export metadata for 'AccountID' is missing and no default value was supplied ".

My code...

Creating the container (in Global.asax or App_Start folder):

// Get assemblies that will be providing imports and exports
var assemblies = GetAssemblies();

// Get conventions that will be used to find imports and exports
var conventions = GetConventions();

var container = new ContainerConfiguration().WithAssemblies(assemblies, conventions).CreateContainer();

// Create and apply a MefControllerFactory so controllers can be composed
ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));

GetConventions() method:

private static ConventionBuilder GetConventions()
{
    var conventionBuilder = new ConventionBuilder();
    conventionBuilder.ForTypesDerivedFrom<IController>().Export();

    conventionBuilder.ForTypesDerivedFrom<IExtension>().Export<IExtension>();
    conventionBuilder.ForTypesMatching(t => t.Namespace != null && t.Namespace.EndsWith(".Parts")).Export().ExportInterfaces();

    return conventionBuilder;
}

IExtension.cs:

public interface IExtension
{
    void DoWork();
}

ExtensionMetadata.cs:

public class ExtensionMetadata
{
    public int AccountID { get; set; }
}

ExtensionA.cs (same as ExtensionB.cs):

public void DoWork()
{
    System.Diagnostics.Debug.WriteLine("ExtensionA doing work..");
}

ExtensionManager.cs:

public class ExtensionManager
{       
    private IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> _extensions;

    public ExtensionManager(IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> extensions)
    {
        _extensions = extensions;
    }

    public void DoWork(int accountID)
    {
        foreach (var extension in _extensions)
        {
            if (extension.Metadata.AccountID == accountID)
            {
                extension.DoWork();
            }                   
        }           
    }
}

I think I'm missing something quite major here. Basically I want to lazily import all Extensions, check their metadata and if a condition is fulfilled have that extension do something.

Would really appreciate your feedback or any links to sample code / tutorials that cover my scenario.

Many thanks!

I think I've worked it out after reading this SO question .

I created a Metadata Attribute:

[MetadataAttribute]
public class ExtensionMetadataAttribute : ExportAttribute, IExtensionMetadata
{
    public int AccountID { get; set; }

    public ExtensionMetadataAttribute(int accountID) : base(typeof (IExtension))
    {
        AccountID = accountID;
    }
}

Then modified ExtensionA.cs:

[ExtensionMetadata(1)]
public class ExtensionA : IExtension
{
    public void DoWork()
    {
        System.Diagnostics.Debug.WriteLine("ExtensionA doing work..");
    }
}

And now ExtensionManager.cs looks like this:

public class ExtensionManager : IExtensionManager
{
    private readonly IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> _extensions;

    public ExtensionManager(IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> extensions)
    {
        _extensions = extensions;
    }

    public void DoWork(int accountID)
    {
        foreach (var extension in _extensions)
        {
            if (extension.Metadata.AccountID == accountID)
            {
                using (var foo = extension.CreateExport())
                {
                    foo.Value.DoWork();
                }
            }
        }
    }
}

This seems to do the trick, but I would still be interested in any feedback re best practices, performance issues etc.

Thanks!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM