在MEF中导出/导入外部类型 - Silverlight

时间:2010-12-02 14:38:38

标签: .net silverlight mef

我正在努力将Pages动态加载到现有的Silverlight应用程序中。到现在为止还挺好。从外部.xap工作导入Pages并将数据从主机应用程序导出到插件都正常工作。

主机应用程序使用Web服务,该Web服务公开与后端系统相关的许多类型。我的问题是如何导出Web服务中定义的类型的对象?

示例i导出SMS_SupportedPlatforms的列表,该列表在WS客户端中定义。这是来自托管应用程序。该属性位于Silverlight主应用程序的App.xaml.cs中。它由对Webservice的异步调用填充。

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

编辑: 我已将Imports移动到外部程序集中的Seperate类。他们现在就读到这堂课:

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

}

此类由要导出的页面的构造函数调用(用于测试目的)。 然后将该页面与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保持为null。如果为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(插件)中,我将大量页面导出到程序集B中的UIProviderbase。页面需要使用程序集A(主要Silverlight应用程序)中的数据。然后,程序集A需要将UIProviderbase作为插件导入,并从中获取一组菜单页面,将它们添加到应用程序中。 这适用于除Web服务中定义的类型之外的所有类型,即程序集A和B都有引用。

2 个答案:

答案 0 :(得分:1)

事实证明,它是某种形式的类型匹配或类型不兼容。在插件(程序集B)中,我添加了对程序集A的引用并使用了那里的类型:

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

我没有用ContractName装饰导出或导入,因为在这种情况下不需要它,并且类型是明确的。

答案 1 :(得分:0)

您的List属性在哪里?

尝试使用:

Container.GetExportedValues<Client.SMS_SupportedPlatforms>()