Derik Whittaker

Syndication

News


Providing Metadata to your MEF exports

Many months ago I created a post on how to get started with MEF.  Ever since then I have been meaning to get this post (and others) about about how to get up and running quickly with MEF.

In this post will demonstrate how to provide Metadata (custom values which can help provide context) information to your Exported item.  Why should you care about Metedata?  Below is a great reason from the MEF site on codeplex

Declaring Exports explained the basics of parts exporting services and values. In some cases it’s necessary to associate information with exports for a variety of reasons. Commonly it’s used to explain about the capabilities of an specific implementation of a common contract. This is useful to allow imports to either constraint the export that can satisfy it, or to import all available implementations at the time and check their capabilities in runtime before using the export.

Before we get rolling:

What I am going to show in this post is how to create a custom Export Attribute.  It is possible to expose Meta via the build in ExportAttribute, but the built in mechanism has a few short comings:

  1. Not discoverable
  2. Not strongly typed
  3. Compiler cannot validate the data content

Lets get rolling:

Pre-Step 1: Taking a look at the Class which we will mark as a Export

    public interface IPlugin
    {
        string PluginAction();
    }

    [Export(typeof(IPlugin))]
    public class DefaultPlugin : IPlugin 
    {
        public string PluginAction()
        {
            return "This is the default plugin";
        }
    }

Step 1: Defining the interface which will represent your

In order to create discoverable Metadata you will first want to create an interface which will represent your metadata.  Below is my interface.

    public interface IPluginMetaData
    {
        string Name { get; }
        string Version { get; } 
    }

We will later use this interface when we define and use our custom Export Attribute.  The main reason for creating this attribute is now the compiler has a hard wired way to know exactly what type of data is being exposed in your Metadaa

Step 2: Defining your custom ExportAttribute Attribute

Now that we created our interface to give us strong typing and discoverability we need to create a custom attribute which will allows the MEF engine to know we have Metadata to expose

    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class PluginMetadataAttribute : ExportAttribute
    {
        public PluginMetadataAttribute( string name, string version)
            : base(typeof(IPluginMetaData))
        {
            Name = name;
            Version = version;
        }

        public string Name { get; set; }
        public string Version { get; set; }
    }

When looking at the code above there are 3 things to pay close attention to

  1. You need to make a call into the base constructor of the ExportAttribute and provide it the type of your interface which defines your Metadata
  2. You need to mark your attribute with the [MetadataAttribute] (which is part of MEF)
  3. You need to mark the usage type of your attribute.  I am not 100% why this is needed (Glenn, you out there with an answer???)

Step 3: Providing your Metdata to your Exported Class

    [Export(typeof(IPlugin))]
    [PluginMetadata("Default", "1.0.0.0")]
    public class DefaultPlugin : IPlugin 
    {
        public string PluginAction()
        {
            return "This is the default plugin";
        }
    }

The code above is the same as the code we saw in pre-step 1, but this time we have marked the class with our custom Metadata attribute.  We have now officially provided our Metadata to our Export…. But how do we get this information out of MEF?

Step 4: Setting up your [ImportMany] to use the Metadata

If you are using an ImportMany (this should also work on an Import, but I have never tried) most likely you are pushing your Exports into a IList or IEnumerable.  If this is the case, your changes are pretty minor.  Below is what you need to do in order to have your Metadata loaded.

[ImportMany(typeof(IPlugin), AllowRecomposition = true)]
private IList<Lazy<IPlugin, IPluginMetaData>> _loadedIPlugins = new List<Lazy<IPlugin, IPluginMetaData>>();

If you have not seen the Lazy keyword, you are not alone.  This is new to .Net 4 and this provides Lazy initialization support to the framework.  (part of the System namespace).  One key thing to understand here though is that the Lazy keyword out the box is only Lazy<T>, but the Lazy we are using is Lazy<T, M>.  This extended version of Lazy lives in the MEF assemblies (System.ComponentModel.Composition) and will need to be referenced to use.

Step 5: Using the Metadata

Once you have the Export loaded into your container (which by the way does not need to change to have this work) you can access your container by selecting the .Metadata property on your instance of the export.  The image below shows it in action.

image

As you can see, exposing and using Metadata via MEF is a snap. 

Till next time,


Posted 03-06-2010 7:07 PM by Derik Whittaker

[Advertisement]

Comments

progg.ru wrote Определение метаданных для экспорта в MEF
on 03-07-2010 12:59 PM

Thank you for submitting this cool story - Trackback from progg.ru

Glenn Block wrote re: Providing Metadata to you MEF exports
on 03-07-2010 2:48 PM

Nice post, and Yes I here :-)

If you don't set AllowMultiple to false, MEF will assume there can be multiple metadata values for each key. As a result it will make the metadata values arrays which will be incompatible with your metadata view unless it's values are also arrays.

There are cases where having multiple values makes sense such as if you have multiple categories. In general in these cases you would probably have a free-form metadata attribute (decorated with MetadataAttribute) which is not an export. This would be annotated on top of an existing export.

Glenn Block wrote re: Providing Metadata to you MEF exports
on 03-07-2010 2:53 PM

As an example of when you would want to use AllowMultiple = true, check this out.

[MetadataAttribute]

[AttributeUsages(AttributeTargets.Class, AllowMultiple=true)]

public class CategoryMetadata : Attribute {

 public string Category {get;set;}

}

The importer for this export would need to have an array, otherwise the exporter would not be matched as we use type as part of the matching and array of string is different than string.

public interface ICategoryView {

  public string[] Category {get;}

}

fkelly3467 wrote re: Providing Metadata to you MEF exports
on 03-08-2010 11:03 AM

Great post sir. Thanks for this it was very helpful

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)