How do catalog publish Recomposition event?

Oct 8, 2009 at 6:32 AM

Let take the following scenario:

How does the following import Recomposition occurs triggered by changes of the catalog:

[Import (AllowRecomposition=true)]

public IEquatable<Lazy<Foo>> Foos { get; set; }

What should I do at the catalog level?

Let take the following custom catalog, filter catalog that the filter criteria has changed

public class FilteredComposablePartCatalog : ComposablePartCatalog
{
    private readonly IQueryable<ComposablePartDefinition> _filteredParts;
    private Func<ComposablePartDefinition, bool> _filter = def => true;

    public Func<ComposablePartDefinition, bool> Filter
    {
        get { return _filter; }
        set
            _filter = value
            // Recomposition needed
        }
 
  }

     public FilteredComposablePartCatalog(ComposablePartCatalog catalog )
  
 {
       
this._filteredParts = catalog.Parts.Where(_filter).AsQueryable();
   
}

 

    public override IQueryable<ComposablePartDefinition> Parts  {
       
get {
              return this._filteredParts;
       
}
   
 }
}

Coordinator
Oct 8, 2009 at 5:29 PM
Edited Oct 8, 2009 at 6:35 PM

 

First, let me warn you that you may want to think twice about using recomposition.  MEF will prevent a recomposition if it would cause an invalid graph (for example removing a required export, or adding a second export that fulfills a contract that an importer expects only one of).  So you should really only use recomposition for scenarios where it is OK for MEF to tell you "no, you can't do that."

Recomposition uses a transaction-type class called AtomicComposition to ensure that any changes can be backed out until they have all been validated.  Your catalog should create an instance of this class, and call AddCompleteAction() on it passing in an Action that will be run to commit the transaction.  The catalog needs to implement the INotifyComposablePartCatalogChanged interface, and it should raise the Changing event.  The Changing event takes a ComposablePartCatalogChangeEventArgs, which should include the part definitions that will be added and removed in the recomposition, as well as the AtomicComposition object.  If MEF rejects the change, a ChangeRejectedException will be thrown when you raise the Changing event, and you should handle that appropriately.  If an exception isn't thrown, then the transaction can be committed, which you can do by calling AtomicComposition.Complete().  Finally, you should raise the Changed event, but this time the AtomicComposition in the EventArgs should be null.

Here is the basic skeleton for what the code should look like:

try
{
    using (var atomic = new AtomicComposition())
    {
        atomic.AddCompleteAction(() => { /* commit catalog change here */ });
        if (Changing != null)
        {
            Changing(this, new ComposablePartCatalogChangeEventArgs(added, removed, atomic));
        }
        atomic.Complete();
    }

    if (Changed != null)
    {
        Changed(this, new ComposablePartCatalogChangeEventArgs(added, removed, null));
    }
}
catch (ChangeRejectedException ex)
{
    //  Change was rejected, handle it however is appropriate
}

EDIT: Also, don't you mean IEnumerable<Lazy<Foo>> instead of IEquatable<Lazy<Foo>> for your import?

Thanks,
Daniel 

Oct 23, 2009 at 5:38 PM

TNX

I tried to use the recomposition API and I found the following difficulties:
Because the recomposition is working on the
ComposablePartDefinition level it seem impossible to notify about changes that was happens to some export within the  ComposablePartDefinition but didn’t affect other export definitions.

I used filter catalog which use to filter export definition upon methods as the test case.
I found no way of notifying about changes that should affect the composition result while some method within the same class match the filter and other not.

It does working well while the export decoration is used on the class level instead of the method level.

You can download the test case from the following link:

http://cid-9bf7c1a515d76a9a.skydrive.live.com/self.aspx/Code%20Samples/MEF/RecompositionFilterCatalog.zip

I suggest to have the event API on the export definition level instead of on the ComposablePartDefinition level.

using (var atomic = new AtomicComposition())
{
    atomic.AddCompleteAction(() => // should tearget the export definition level