Экспорт / импорт внешних типов в MEF - Silverlight - PullRequest
2 голосов
/ 02 декабря 2010

Я работаю над реализацией динамической загрузки страниц в существующее приложение Silverlight. Все идет нормально. Работает как импорт страниц из работы внешнего .xap, так и экспорт данных из хост-приложения в плагины.

Хост-приложение использует веб-сервис, который предоставляет несколько типов, относящихся к бэкэнд-системе. Мой вопрос: как мне экспортировать объекты типов, определенных в веб-сервисе?

Пример. I Экспорт списка SMS_SupportedPlatforms, который определен в клиенте WS. Это из хостинг-приложения. Свойство находится в App.xaml.cs основного приложения Silverlight. Он заполняется асинхронным вызовом веб-службы.

 [Export(ExportContracts.SMS_SupportedPlatforms)]
    public static List<Client.SMS_SupportedPlatforms> SupportedPlatforms = new List<Client.SMS_SupportedPlatforms>(); 

Отредактировано: Я переместил Imports в отдельный класс во внешних сборках. Теперь они читают в этом классе:

public class NeoServiceManagerImports
{
        [Import(NeoSMExportContracts.DepartmentExportAttribute, AllowRecomposition = true)]
        public string Department { get; set; }

        [Import(NeoSMExportContracts.RolesExportAttribute, AllowRecomposition = true)]
        public List<string> Roles { get; set; }



        [Import(NeoSMExportContracts.SMS_SupportedPlatforms, AllowRecomposition = true)]
        public List<Client.SMS_SupportedPlatforms> SupportedPlatforms
        {
            get;
            set;
        }

        public NeoServiceManagerImports()
        {
            CompositionInitializer.SatisfyImports(this);
        }
*

} * 1013

Этот класс вызывается конструктором страницы для экспорта (в целях тестирования). Затем страница экспортируется с атрибутом MetadataAttribute в класс UIProviderbase, который я предложил для экспорта плагинов (игнорируйте очень абстрактное именование ;-)) В классе есть несколько реквизитов для логотипа, названия и списка страниц.

[Export(typeof(UIProviderBase))]
    public class ExternalMainMenuExternalSubMenuUIProvider: UIProviderBase
    {

        public override string Title
        {
            get { return "Submenu"; }
        }

        public override string ImageUri
        {
            get { return "uriuri"; }
        }

        [ImportMany("ExternalSubMenuForExternalMainMenuContract")]
        public override List<System.ComponentModel.Composition.ExportFactory<FrameworkElement, IPageMetadata>> EntryPage
        {
            get;
            set;
        }
    }

Я уверен, что проблема связана с тем, что MEF не может разрешить тип как один и тот же, когда на него ссылаются две разные сборки. Есть ли способ решить эту проблему, без рефакторинга хост-приложения, чтобы получить список ISMS_SupportedPlatforms? В настоящее время кажется, что приложение хостинга экспортируется правильно, но оно никогда не обнаруживается в плагине.

Если у меня AllowDefault = true, страница загружается, но SupportedPlatforms остается нулевым. Если false, он не экспортирует страницу и молча завершается неудачей.

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

The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

1) No valid exports were found that match the constraint '((exportDefinition.ContractName == "SMS_SupportPlatformsExport") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "System.Collections.Generic.List(HelloWorld.MEF.Client.SMS_SupportedPlatforms)".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))', invalid exports may have been rejected.

Resulting in: Cannot set import 'HelloWorld.MEF.NeoServiceManagerImports.SupportedPlatforms (ContractName="SMS_SupportPlatformsExport")' on part 'HelloWorld.MEF.NeoServiceManagerImports'.
Element: HelloWorld.MEF.NeoServiceManagerImports.SupportedPlatforms (ContractName="SMS_SupportPlatformsExport") -->  HelloWorld.MEF.NeoServiceManagerImports

Resulting in: An exception occurred while trying to create an instance of type 'HelloWorld.MEF.ExternalMainMenuExternalSubMenu'.

Resulting in: Cannot activate part 'HelloWorld.MEF.ExternalMainMenuExternalSubMenu'.
Element: HelloWorld.MEF.ExternalMainMenuExternalSubMenu -->  HelloWorld.MEF.ExternalMainMenuExternalSubMenu -->  AssemblyCatalog (Assembly="HelloWorld.MEF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

Resulting in: Cannot get export 'HelloWorld.MEF.ExternalMainMenuExternalSubMenu (ContractName="ExternalSubMenuForExternalMainMenuContract")' from part 'HelloWorld.MEF.ExternalMainMenuExternalSubMenu'.
Element: HelloWorld.MEF.ExternalMainMenuExternalSubMenu (ContractName="ExternalSubMenuForExternalMainMenuContract") -->  HelloWorld.MEF.ExternalMainMenuExternalSubMenu -->  AssemblyCatalog (Assembly="HelloWorld.MEF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

Это код, где появляется исключение

var page = (from p in this.Plugins
                    from e in p.EntryPage
                    where e.Metadata.NavigateUri == this.targetUri.ToString()
                    select e).Single().CreateExport().Value;

Проживание в этом классе (загрузка страниц динамически)

public class MefContentLoader : INavigationContentLoader
    {
        private PageResourceContentLoader pageResourceContentLoader = new PageResourceContentLoader();
        private Uri targetUri;

        [ImportMany(AllowRecomposition = true)]
        public UIProviderBase[] Plugins
        {
            get;
            set;
        }

        public MefContentLoader()
        {
            CompositionInitializer.SatisfyImports(this);
        }

        #region INavigationContentLoader Members

        public IAsyncResult BeginLoad(Uri targetUri, Uri currentUri, AsyncCallback userCallback, object asyncState)
        {
            this.targetUri = targetUri;
            return pageResourceContentLoader.BeginLoad(targetUri, currentUri, userCallback, asyncState);
        }

        public bool CanLoad(Uri targetUri, Uri currentUri)
        {
            // TODO: Handle this properly
            return true;
        }

        public void CancelLoad(IAsyncResult asyncResult)
        {
            // TODO: Handle this properly
            pageResourceContentLoader.CancelLoad(asyncResult);
        }

        public LoadResult EndLoad(IAsyncResult asyncResult)
        {
            if (this.Plugins.Length == 0 ||
                this.Plugins.Count(p => p.EntryPage != null && p.EntryPage.Any(u => u.Metadata.NavigateUri == targetUri.ToString())) == 0)
            {
                return pageResourceContentLoader.EndLoad(asyncResult);
            }

            var page = (from p in this.Plugins
                    from e in p.EntryPage
                    where e.Metadata.NavigateUri == this.targetUri.ToString()
                    select e).Single().CreateExport().Value;

            return new LoadResult(page);
        }

        #endregion


    }

Подводя итог: В сборке B (плагин) я экспортирую несколько страниц в UIProviderbase в сборке B. Страницы должны использовать данные из сборки A (основное приложение Silverlight). Сборка A затем должна импортировать UIProviderbase в виде плагинов, и из них получить коллекцию страниц меню, добавляя их в приложение. Это работает со всеми, кроме типа, определенного в веб-сервисе, на который ссылаются обе сборки A и B.

Ответы [ 2 ]

1 голос
/ 09 декабря 2010

Оказывается, это была какая-то форма совпадения типов или несовместимости типов.В плагине (Сборка B) я добавил ссылку на Сборку A и использовал оттуда тип:

[Import(AllowRecomposition = true)]
public Lazy<List<NeoServiceManager.Client.SMS_SupportedPlatforms>> SupportedPlatforms
{
    get;
    set;
}

Я не оформлял экспорт или импорт с помощью ContractName, так как в этом случае он не нужени тип однозначен.

0 голосов
/ 03 декабря 2010

Где живет ваша недвижимость в Списке?

Попробуйте использовать:

Container.GetExportedValues<Client.SMS_SupportedPlatforms>()
...