OK I'm pretty sure this is something blindingly obvious but I'm not finding it.
I'm trying to export a object from MEF container based on it's Metadata.
I've seen this done in tutorials like this one:
However my export doesn't have the Metadata property that is necessary for this to work. What could be the problem there?
[Export(typeof(IController))]
[ExportMetadata("controllerName","Home")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : Controller{}
and again
public class MyControllerFactory : IControllerFactory
{
private readonly CompositionContainer _container;
public MyControllerFactory(CompositionContainer container)
{
_container = container;
}
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
var controllerExport = _container.GetExports<IController>().
Where(exp => exp.Metadata) //Here it doesn't have the Metadata property.
}
}
I understand that the GetExports returns a collection of Lazy that do of course not have the Metadata property but it's assumed in most tutorials I look through.
How do I do this correctly?
This is what I did:
public interface IControllerMetaData
{
string Name { get; }
string Subdomain { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class ControllerMetadataAttribute : ExportAttribute
{
public ControllerMetadataAttribute(string name, string subdomain)
: base(typeof(IControllerMetaData))
{
Name = name;
Subdomain = subdomain;
}
public string Name { get; set; }
public string Subdomain { get; set; }
}
Then in each controller
[Export(typeof(IController))]
[ControllerMetadata("Home", "")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : SubdomainManagedController
and in the factory
var controllerExport = _container.GetExports<IController, ControllerMetadataAttribute>().
Where(exp => exp.Metadata.Name.Equals(controllerName) && exp.Metadata.Subdomain.Equals(subdomain)).
FirstOrDefault();
and I'm getting
The Type 'ControllerMetadataAttribute' supplied is not a valid Metadata View.`
How is it not valid. It has the MetaDataAttribute and all?
In your example, you're using GetExports<T>
, instead of GetExports<T,TMetadata>
. In a simple example, you can use GetExports<IController, IDictionary<string, object>>
, which would allow you to query, but a nicer way of doing it is to create a custom metadata contract:
public interface INameMetadata
{
string Name { get; }
}
Which you can then use as:
[Export(typeof(IController))]
[ExportMetadata("Name", "Home")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : Controller { }
And then change your import to:
var controller = _container.GetExports<IController, INameMetadata>()
.Where(e => e.Metadata.Name.Equals(controllerName))
.Select(e => e.Value)
.FirstOrDefault();
Going one step further, you could combine your Export
and ExportMetadata
attributes into a single attribute:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false), MetadataAttribute]
public class ExportControllerAttribute : ExportAttribute, INameMetadata
{
public ExportControllerAttribute(string name)
: base(typeof(IController))
{
Name = name;
}
public string Name { get; private set; }
}
Now, you can use that with your export:
[ExportController("Home"), PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : Controller { }