Метаданные со строгой типизацией в MEF2 (System.Composition)

Я использую пространство имен System.Composition из MEF для пакета NuGet для веб-приложений и приложений Магазина Windows в новом проекте ASP.NET MVC4.

Я читал, что в MEF2 вы больше не используете Lazy<IExtension, IExtensionMetadata>, но теперь вы должны предоставить конкретный тип для представления метаданных (и, возможно, использовать ExportFactory<> вместо Lazy<>?).

Однако я не могу найти никаких примеров того, как все это должно работать - лишь несколько упоминаний об использовании конкретного типа вместо интерфейса.

Я пробовал несколько вещей, но продолжаю получать следующую ошибку - "Экспорт метаданных для" AccountID "отсутствует, и значение по умолчанию не было предоставлено".

Мой код...

Создание контейнера (в папке Global.asax или App_Start):

// 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():

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 (такой же, как 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();
            }                   
        }           
    }
}

Я думаю, что мне здесь чего-то не хватает. По сути, я хочу лениво импортировать все расширения, проверить их метаданные и, если условие выполнено, сделать это расширение.

Буду очень признателен за ваши отзывы или любые ссылки на примеры кода / учебники, которые охватывают мой сценарий.

Большое спасибо!

1 ответ

Я думаю, что я решил это после прочтения этого ТАКОГО вопроса.

Я создал атрибут метаданных:

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

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

Затем изменил ExtensionA.cs:

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

И теперь ExtensionManager.cs выглядит так:

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

Это, кажется, делает свое дело, но я все еще был бы заинтересован в любой обратной связи относительно лучших практик, проблем с производительностью и т. Д.

Спасибо!

Другие вопросы по тегам