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