MEF и экспорт на основе метаданных - PullRequest
11 голосов
/ 05 октября 2011

Хорошо, я уверен, что это что-то ослепительно очевидное, но я не нахожу это.

Я пытаюсь экспортировать объект из контейнера MEF на основе его метаданных.

Я видел, как это было сделано в следующих уроках:

http://blog.maartenballiauw.be/post/2009/04/21/ASPNET-MVC-and-the-Managed-Extensibility-Framework-%28MEF%29.aspx

Однако мой экспорт не имеет свойства Metadata, необходимого для его работы. В чем может быть проблема?

[Export(typeof(IController))]
[ExportMetadata("controllerName","Home")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : Controller{}

и снова

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

Я понимаю, что GetExports возвращает коллекцию Lazy, у которой, конечно, нет свойства Metadata, но это предполагается в большинстве учебных пособий, которые я просматриваю.

Как мне сделать это правильно?

EDIT

Вот что я сделал:

 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; }
}

Тогда в каждом контроллере

[Export(typeof(IController))]
[ControllerMetadata("Home", "")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : SubdomainManagedController

и на заводе

var controllerExport = _container.GetExports<IController, ControllerMetadataAttribute>().
                                    Where(exp => exp.Metadata.Name.Equals(controllerName) && exp.Metadata.Subdomain.Equals(subdomain)).
                                    FirstOrDefault();

и я получаю

Предоставленный тип ControllerMetadataAttribute не является допустимым представлением метаданных.

Как это не действует. У него есть MetaDataAttribute и все?

1 Ответ

19 голосов
/ 05 октября 2011

В вашем примере вы используете GetExports<T> вместо GetExports<T,TMetadata>.В простом примере вы можете использовать GetExports<IController, IDictionary<string, object>>, что позволит вам делать запросы, но лучший способ сделать это - создать собственный контракт метаданных:

public interface INameMetadata
{
    string Name { get; }
}

, который затем можно использовать как:

[Export(typeof(IController))]
[ExportMetadata("Name", "Home")]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : Controller { }

А затем измените свой импорт на:

var controller = _container.GetExports<IController, INameMetadata>()
                           .Where(e => e.Metadata.Name.Equals(controllerName))
                           .Select(e => e.Value)
                           .FirstOrDefault();

Если пойти еще дальше, вы можете объединить свои атрибуты Export и ExportMetadata в один атрибут:

[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; }
}

Теперь вы можете использовать это в своем экспорте:

[ExportController("Home"), PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : Controller { }
...