Necessary to AllowRecomposition on all Imports to do XAP partitioning?!

Dec 7, 2010 at 8:50 PM

I am using Glenn Block's technique using DeploymentCatalog to be able to load XAPs on the fly as different pages are loaded.

The problem is as soon as a you load a new XAP, MEF seems to start to recompose every single import it can find, and fails because lots of them are instance variables that you wouldn't want to change.

So how the heck do you make this work w/o adding AllowRecomposition=true to every single [Import]?

Dec 7, 2010 at 8:58 PM

MEF requires that any import that is existing in the catalog be recomposable if new catalogs are added that contain the contract that is being added. In other words if in your existing catalog you have a part that imports IFoo or IBar, and then a new implementation of IFoo or IBar shows up in the catalog, then it will get rejected unless IFoo and IBar are recomposble.

Can you describe a bit more of your scenario / contents of the catalogs in the app and being downloaded, and which are recomposable?

Thanks
Glenn

Dec 7, 2010 at 9:19 PM

It seems to work when the class you're loading the AggregateCatalog from has an [Export] on it.  The problem arises when you aren't exporting this class so you have:

CompositionInitializer.SatisfyImports(this);

instead in your constructor.

Essentially I have a navigation Page class.  When the page loads, I want to load a XAP, find an exported control with the right attribute, and display it in the Page.  So the Page class has no [Export]:

public partial class MyPage : Page, IPartImportsSatisfiedNotification
    {
        public const string module = "MyModule.xap";
        
        [Import]
        public IDeploymentCatalogService CatalogService { get; set; }

        public MyPage()
        {
            InitializeComponent();
            CompositionInitializer.SatisfyImports(this);
        }

        public void OnImportsSatisfied()
        {
            CatalogService.AddXap(module, args =>
            {
                if (args.Error != null)
                    // display error
                else
                {
                    // get control and stuff it in LayoutRoot
                }
            });
        }
}

 

Dec 7, 2010 at 9:35 PM

Here is the error MEF gives when I try to load the module:

The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced multiple composition errors, with 38 root causes. The root causes are provided below. Review the CompositionException.Errors property for more detailed information.
1) Change in exports prevented by non-recomposable import 'MyCompany.Client.App.MenuViewModel (ContractName="MenuViewModel")' on part 'MyCompany.Client.App'.
2) Change in exports prevented by non-recomposable import 'MyCompany.Client.App.SaveViewModel (ContractName="SaveViewModel")' on part 'MyCompany.Client.App'.
3) Change in exports prevented by non-recomposable import 'MyCompany.Client.App.UserContext (ContractName="MyCompany.Client.Common.UserContext")' on part 'MyCompany.Client.App'.
4) Change in exports prevented by non-recomposable import 'MyCompany.Client.Admin.ViewModel (ContractName="AdminViewModel")' on part 'MyCompany.Client.Admin'.

[...lots more, every import in my app, singleton stuff that didn't change...]

I have no problem recomposing imports that actually may have changed by the load of the new XAP, but it seems to be reloading everything here.

Dec 8, 2010 at 12:05 AM

I have a few ideas, but it's hard to tell from here. It all depends on what ts in the xaps. Can you possibly post your sample / repro or send it via email to gblock@microsoft.com.

Thanks

Dec 8, 2010 at 3:28 AM

I'm putting together a sample app, will get it to you tomorrow.  Having trouble reproducing the error in the sample app so it does seem like it's something in my app that's tripping MEF up.

Thanks very much for your help, Glenn.

Dec 8, 2010 at 3:32 AM

No problem.

Glenn

Feb 17, 2011 at 2:04 PM

Hi, I'm having a similar problem. I am using MEF to dynamically loading xap's files and I'm getting the following error:

System.ComponentModel.Composition.ChangeRejectedException was unhandled by user code
  Message=The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced multiple composition errors, with 7 root causes.
  The root causes are provided below. Review the CompositionException.Errors property for more detailed information.

1) Change in exports prevented by non-recomposable import 'VitalCASTWeb.MainPage.ViewModel (ContractName="VitalCASTWeb.ViewModels.MainPageViewModel")' on part 'VitalCASTWeb.MainPage'.

2) Change in exports prevented by non-recomposable import 'VitalCASTWeb.ViewModels.MainPageViewModel.Catalog (ContractName="VitalCASTWeb.Infrastructure.IDeploymentCatalogService")'
 on part 'VitalCASTWeb.ViewModels.MainPageViewModel'.

3) Change in exports prevented by non-recomposable import 'VitalCASTWeb.Infrastructure.ViewModelBase.ServiceAgent (ContractName="VitalCASTWeb.Infrastructure.IServiceAgent")'
 on part 'VitalCASTWeb.ViewModels.MainPageViewModel'.

4) Change in exports prevented by non-recomposable import 'VitalCASTWeb.ViewModels.MainPageViewModel.Catalog (ContractName="VitalCASTWeb.Infrastructure.IDeploymentCatalogService")'
 on part 'VitalCASTWeb.ViewModels.MainPageViewModel'.

5) Change in exports prevented by non-recomposable import 'VitalCASTWeb.Infrastructure.ViewModelBase.ServiceAgent (ContractName="VitalCASTWeb.Infrastructure.IServiceAgent")'
 on part 'VitalCASTWeb.ViewModels.MainPageViewModel'.

6) Change in exports prevented by non-recomposable import 'VitalCASTWeb.ViewModels.MainPageViewModel.Catalog (ContractName="VitalCASTWeb.Infrastructure.IDeploymentCatalogService")'
 on part 'VitalCASTWeb.ViewModels.MainPageViewModel'.

7) Change in exports prevented by non-recomposable import 'VitalCASTWeb.Infrastructure.ViewModelBase.ServiceAgent (ContractName="VitalCASTWeb.Infrastructure.IServiceAgent")'
 on part 'VitalCASTWeb.ViewModels.MainPageViewModel'.

  StackTrace:
       at VitalCASTWeb.Infrastructure.DeploymentCatalogService.CatalogDownloadCompleted(Object sender, AsyncCompletedEventArgs e)
       at System.ComponentModel.Composition.Hosting.DeploymentCatalog.OnDownloadCompleted(AsyncCompletedEventArgs e)
       at System.ComponentModel.Composition.Hosting.DeploymentCatalog.HandleOpenReadCompleted(Object sender, OpenReadCompletedEventArgs e)
       at System.Net.WebClient.OnOpenReadCompleted(OpenReadCompletedEventArgs e)
       at System.Net.WebClient.OpenReadOperationCompleted(Object arg)
  InnerException:

Sorry for my English but its not my primary language.

I hope you can help me. Thanks

Feb 17, 2011 at 3:16 PM

Frank, I was never able to come up with a stripped down sample app that reproduces the error (Sorry Glenn).  If you can, perhaps you can send it to him.

I have moved away from Silverlight and MEF to WPF and Unity/Prism so this is no longer a concern for me.  I would be interested, however, to know if there is a resolution.