MEF Recomposition

Il DirectoryWatcherCatalog introdotto in uno dei post precedenti ci introduce ad una caratteristica molto importante di MEF chiamata Recomposition.

Che cos’è?
La recomposition permette “a MEF” di aggiornare gli import quando vengono aggiunti nuovi export.

Per cui nel caso del DirectoryWatcherCatalog quando aggiungiamo una dll all’interno della directory monitorata, la lista di plugins (definita di seguito) dovrebbe essere aggiornata automaticamente da MEF.

   1: [ImportMany(typeof(IPlugin))]
   2: public ObservableCollection<IPlugin> Plugins { get; set; }

Dovrebbe?!? Si dovrebbe perchè quando aggiungiamo il plugin alla directory monitorata otteniamo una ChangeRejectedException

image

dove il messaggio di errore è

The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

1) Change in exports prevented by non-recomposable import 'IntroductionToMEFSample.ViewModels.MainViewModel.Plugins (ContractName="MEFSample.Contracts.IPlugin")' on part 'IntroductionToMEFSample.ViewModels.MainViewModel'.

 

Perchè non funziona? E come facciamo a far funzionare tutto l’ambaradan?
Non funziona in quanto il comportamento standard di MEF non permette la recomposition e per far funzionare il tutto basta semplicemente settare la propietà AllowRecomposition dell’attributo Import/ImportMany a true

   1: [ImportMany(typeof(IPlugin), AllowRecomposition = true)]
   2: public ObservableCollection<IPlugin> Plugins { get; set; }

Se la classe che espone la proprietà Plugins implementa l’interfaccia IPartImportsSatisfiedNotification il metodo OnImportsSatisfied verrà chiamato ogni volta che avviene la recomposition. Un’altra maniera per sapere quando avviene la recomposition o più in generale quando cambiano gli Exports è sottoscrivere uno di questi due eventi del CompositionContainer

   1: /// <summary>
   2: ///     Occurs when the exports in the <see cref="ExportProvider"/>
   3: ///     have changed.
   4: /// </summary>
   5: public event EventHandler<ExportsChangeEventArgs> ExportsChanged;
   6:  
   7: /// <summary>
   8: ///     Occurs when the exports in the <see cref="ExportProvider"/>
   9: ///     are changing.
  10: /// </summary>
  11: public event EventHandler<ExportsChangeEventArgs> ExportsChanging;

Nei post a seguire parleremo di Metadata e se il tempo permette vi mostrerò il plugin manager che uso all’interno delle mie applicazioni!
Per cui stay tuned :D