private void OnExportsChanging(object sender, ExportsChangeEventArgs e)
        {
            CompositionResult result = CompositionResult.SucceededResult;

            // Prepare for the recomposition effort by minimizing the amount of work we'll have to do later
            AtomicComposition atomicComposition = e.AtomicComposition;

            IEnumerable <PartManager> affectedParts = _recompositionManager.GetAffectedParts(e.ChangedContractNames);

            // When in a atomicComposition account for everything that isn't yet reflected in the
            // index
            if (atomicComposition != null)
            {
                EngineContext engineContext;
                if (atomicComposition.TryGetValue(this, out engineContext))
                {
                    // always added the new part managers to see if they will also be
                    // affected by these changes
                    affectedParts = affectedParts.ConcatAllowingNull(engineContext.GetAddedPartManagers())
                                    .Except(engineContext.GetRemovedPartManagers());
                }
            }

            var changedExports = e.AddedExports.ConcatAllowingNull(e.RemovedExports);

            foreach (var partManager in affectedParts)
            {
                result = result.MergeResult(TryRecomposeImports(partManager, changedExports, atomicComposition));
            }

            result.ThrowOnErrors(atomicComposition);
        }
Exemple #2
0
        private CompositionResult TrySatisfyImportSubset(PartManager partManager,
                                                         IEnumerable <ImportDefinition> imports, AtomicComposition atomicComposition)
        {
            CompositionResult result = CompositionResult.SucceededResult;

            var part = partManager.Part;

            foreach (ImportDefinition import in imports)
            {
                var exports = partManager.GetSavedImport(import);

                if (exports == null)
                {
                    CompositionResult <IEnumerable <Export> > exportsResult = TryGetExports(
                        this._sourceProvider, part, import, atomicComposition);

                    if (!exportsResult.Succeeded)
                    {
                        result = result.MergeResult(exportsResult.ToResult());
                        continue;
                    }
                    exports = exportsResult.Value.AsArray();
                }

                if (atomicComposition == null)
                {
                    result = result.MergeResult(
                        partManager.TrySetImport(import, exports));
                }
                else
                {
                    partManager.SetSavedImport(import, exports, atomicComposition);
                }
            }
            return(result);
        }
Exemple #3
0
        public void Compose(CompositionBatch batch)
        {
            ThrowIfDisposed();
            EnsureRunning();

            Requires.NotNull(batch, nameof(batch));

            // Quick exit test can be done prior to cloning since it's just an optimization, not a
            // change in behavior
            if ((batch.PartsToAdd.Count == 0) && (batch.PartsToRemove.Count == 0))
            {
                return;
            }

            CompositionResult result = CompositionResult.SucceededResult;

            // Get updated parts list and a cloned batch
            var newParts = GetUpdatedPartsList(ref batch);

            // Allow only recursive calls from the import engine to see the changes until
            // they've been verified ...
            using (var atomicComposition = new AtomicComposition())
            {
                // Don't allow reentrant calls to compose during previewing to prevent
                // corrupted state.
                if (_currentlyComposing)
                {
                    throw new InvalidOperationException(SR.ReentrantCompose);
                }

                _currentlyComposing = true;

                try
                {
                    // In the meantime recursive calls need to be able to see the list as well
                    atomicComposition.SetValue(this, newParts);

                    // Recompose any existing imports effected by the these changes first so that
                    // adapters, resurrected parts, etc. can all play their role in satisfying
                    // imports for added parts
                    Recompose(batch, atomicComposition);

                    // Ensure that required imports can be satisfied
                    foreach (ComposablePart part in batch.PartsToAdd)
                    {
                        // collect the result of previewing all the adds in the batch
                        try
                        {
                            ImportEngine.PreviewImports(part, atomicComposition);
                        }
                        catch (ChangeRejectedException ex)
                        {
                            result = result.MergeResult(new CompositionResult(ex.Errors));
                        }
                    }

                    result.ThrowOnErrors(atomicComposition);

                    // Complete the new parts since they passed previewing.`
                    using (_lock.LockStateForWrite())
                    {
                        _parts = newParts;
                    }

                    atomicComposition.Complete();
                }
                finally
                {
                    _currentlyComposing = false;
                }
            }

            // Satisfy Imports
            // - Satisfy imports on all newly added component parts
            foreach (ComposablePart part in batch.PartsToAdd)
            {
                result = result.MergeResult(CompositionServices.TryInvoke(() =>
                                                                          ImportEngine.SatisfyImports(part)));
            }

            // return errors
            result.ThrowOnErrors();
        }
        public void Compose(CompositionBatch batch)
        {
            this.ThrowIfDisposed();
            this.EnsureRunning();

            Requires.NotNull(batch, "batch");

            // Quick exit test can be done prior to cloning since it's just an optimization, not a
            // change in behavior
            if ((batch.PartsToAdd.Count == 0) && (batch.PartsToRemove.Count == 0))
            {
                return;
            }

            CompositionResult result = CompositionResult.SucceededResult;

            // Clone the batch, so that the external changes wouldn't happen half-way thorugh compose
            // NOTE : this does not guarantee the atomicity of cloning, which is not the goal anyway,
            // rather the fact that all subsequent calls will deal with an unchanging batch
            batch = new CompositionBatch(batch.PartsToAdd, batch.PartsToRemove);

            var newParts = GetUpdatedPartsList(batch);

            // Allow only recursive calls from the import engine to see the changes until
            // they've been verified ...
            using (var atomicComposition = new AtomicComposition())
            {
                // Don't allow reentrant calls to compose during previewing to prevent
                // corrupted state.
                if (this._currentlyComposing)
                {
                    throw new InvalidOperationException(Strings.ReentrantCompose);
                }

                this._currentlyComposing = true;

                try
                {
                    // In the meantime recursive calls need to be able to see the list as well
                    atomicComposition.SetValue(this, newParts);

                    // Recompose any existing imports effected by the these changes first so that
                    // adapters, resurrected parts, etc. can all play their role in satisfying
                    // imports for added parts
                    this.Recompose(batch, atomicComposition);

                    // Ensure that required imports can be satisfied
                    foreach (ComposablePart part in batch.PartsToAdd)
                    {
                        // collect the result of previewing all the adds in the batch
                        try
                        {
                            this._importEngine.PreviewImports(part, atomicComposition);
                        }
                        catch (ChangeRejectedException ex)
                        {
                            result = result.MergeResult(new CompositionResult(ex.Errors));
                        }
                    }

                    result.ThrowOnErrors(atomicComposition);

                    // Complete the new parts since they passed previewing.`
                    using (this._lock.LockStateForWrite())
                    {
                        this._parts = newParts;
                    }

                    atomicComposition.Complete();
                }
                finally
                {
                    this._currentlyComposing = false;
                }
            }

            // Satisfy Imports
            // - Satisfy imports on all newly added component parts
            foreach (ComposablePart part in batch.PartsToAdd)
            {
                result = result.MergeResult(CompositionServices.TryInvoke(() =>
                                                                          this._importEngine.SatisfyImports(part)));
            }

            // return errors
            result.ThrowOnErrors();
        }