private string GetChangeRejectedExceptionMessage(ChangeRejectedException changeRejectedException) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Errors:"); foreach (var error in changeRejectedException.Errors) { stringBuilder.AppendLine(" " + error.Description); } if (changeRejectedException.RootCauses.Count > 0) { stringBuilder.AppendLine(""); stringBuilder.AppendLine("Root causes:"); foreach (var exception in changeRejectedException.RootCauses) { string rootCauseMessage = null; var compositionException = exception as CompositionException; if (compositionException != null) { rootCauseMessage = compositionException.Message; } else { rootCauseMessage = exception.Message; } stringBuilder.AppendLine(" " + rootCauseMessage); } } return(stringBuilder.ToString()); }
protected virtual void RecompositionException(ChangeRejectedException changeRejectedException) { if (throwOnRecompositionException) { throw changeRejectedException; } }
internal static void PartDefinitionRejected(ComposablePartDefinition definition, ChangeRejectedException exception) { Assumes.NotNull(definition, exception); if (CompositionTraceSource.CanWriteWarning) { CompositionTraceSource.WriteWarning(CompositionTraceId.Rejection_DefinitionRejected, Strings.CompositionTrace_Rejection_DefinitionRejected, definition.GetDisplayName(), exception.Message); } }
private void AddOrDeleteChanging(ComposablePartCatalogChangeEventArgs changeArgs, Action addDeleteAction, bool added) { bool changeException = false; ChangeRejectedException changeRejectedException = null; string failureDetails = null; bool recompositionSuccess = false; RecompositionEventReason recompositionEventReason = RecompositionEventReason.Deleted; try { Changing?.Invoke(this, changeArgs); } catch (ChangeRejectedException exc) { failureDetails = GetChangeRejectedExceptionMessage(exc); changeException = true; } addDeleteAction(); Changed?.Invoke(this, changeArgs); if (!changeException) { recompositionSuccess = true; } else { RecompositionException(changeRejectedException); } if (added) { recompositionEventReason = RecompositionEventReason.Added; } RecompositionAttemptEvent?.Invoke(this, new RecompositionAttemptEventArgs(recompositionSuccess, recompositionEventReason, failureDetails)); }
private bool DetermineRejection(ComposablePartDefinition definition, AtomicComposition parentAtomicComposition) { ChangeRejectedException exception = null; // if there is no active atomic composition and rejection is disabled, there's no need to do any of the below if (!EnsureRejection(parentAtomicComposition)) { return(false); } using (var localAtomicComposition = new AtomicComposition(parentAtomicComposition)) { // The part definition we're currently working on is treated optimistically // as if we know it hasn't been rejected. This handles recursion, and if we // later decide that it has been rejected we'll discard all nested progress so // all side-effects of the mistake are erased. // // Note that this means that recursive failures that would be detected by the // import engine are not discovered by rejection currently. Loops among // prerequisites, runaway import chains involving factories, and prerequisites // that cannot be fully satisfied still result in runtime errors. Doing // otherwise would be possible but potentially expensive - and could be a v2 // improvement if deemed worthwhile. UpdateAtomicCompositionQueryForPartEquals(localAtomicComposition, definition, AtomicCompositionQueryState.TreatAsValidated); var newPart = definition.CreatePart(); try { _importEngine.PreviewImports(newPart, localAtomicComposition); // Reuse the partially-fleshed out part the next time we need a shared // instance to keep the expense of pre-validation to a minimum. Note that // _activatedParts holds references to both shared and non-shared parts. // The non-shared parts will only be used for rejection purposes only but // the shared parts will be handed out when requested via GetExports as // well as be used for rejection purposes. localAtomicComposition.AddCompleteActionAllowNull(() => { using (_lock.LockStateForWrite()) { if (!_activatedParts.ContainsKey(definition)) { _activatedParts.Add(definition, new CatalogPart(newPart)); IDisposable newDisposablePart = newPart as IDisposable; if (newDisposablePart != null) { _partsToDispose.Add(newDisposablePart); } } } }); // Success! Complete any recursive work that was conditioned on this part's validation localAtomicComposition.Complete(); return(false); } catch (ChangeRejectedException ex) { exception = ex; } } // If we've reached this point then this part has been rejected so we need to // record the rejection in our parent composition or execute it immediately if // one doesn't exist. parentAtomicComposition.AddCompleteActionAllowNull(() => { using (_lock.LockStateForWrite()) { _rejectedParts.Add(definition); } CompositionTrace.PartDefinitionRejected(definition, exception); }); if (parentAtomicComposition != null) { UpdateAtomicCompositionQueryForPartEquals(parentAtomicComposition, definition, AtomicCompositionQueryState.TreatAsRejected); } return(true); }
internal static void PartDefinitionRejected(ComposablePartDefinition definition, ChangeRejectedException exception) { if (definition == null) { throw new ArgumentNullException(nameof(definition)); } if (exception == null) { throw new ArgumentNullException(nameof(exception)); } if (CompositionTraceSource.CanWriteWarning) { CompositionTraceSource.WriteWarning(CompositionTraceId.Rejection_DefinitionRejected, SR.CompositionTrace_Rejection_DefinitionRejected, definition.GetDisplayName(), exception.Message); } }