private void ReleasePart(object exportedValue, CatalogPart catalogPart, AtomicComposition atomicComposition)
        {
            this.ThrowIfDisposed();
            this.EnsureRunning();

            Assumes.NotNull(catalogPart);

            this._importEngine.ReleaseImports(catalogPart.Part, atomicComposition);

            if (exportedValue != null)
            {
                atomicComposition.AddCompleteActionAllowNull(() =>
                {
                    this.AllowPartCollection(exportedValue);
                });
            }

            IDisposable diposablePart = catalogPart.Part as IDisposable;

            if (diposablePart != null)
            {
                atomicComposition.AddCompleteActionAllowNull(() =>
                {
                    bool removed = false;
                    using (this._lock.LockStateForWrite())
                    {
                        removed = this._partsToDispose.Remove(diposablePart);
                    }
                    if (removed)
                    {
                        diposablePart.Dispose();
                    }
                });
            }
        }
示例#2
0
        private void OnCatalogChanging(object sender, ComposablePartCatalogChangeEventArgs e)
        {
            using (var atomicComposition = new AtomicComposition(e.AtomicComposition))
            {
                // Save the preview catalog to use in place of the original while handling
                // this event
                atomicComposition.SetValue(this._catalog,
                                           new CatalogChangeProxy(this._catalog, e.AddedDefinitions, e.RemovedDefinitions));

                IEnumerable <ExportDefinition> addedExports = e.AddedDefinitions
                                                              .SelectMany(part => part.ExportDefinitions)
                                                              .ToArray();
                IEnumerable <ExportDefinition> removedExports = e.RemovedDefinitions
                                                                .SelectMany(part => part.ExportDefinitions)
                                                                .ToArray();

                // Remove any parts based on eliminated definitions (in a atomicComposition-friendly
                // fashion)
                foreach (var definition in e.RemovedDefinitions)
                {
                    ComposablePart removedPart = null;
                    bool           removed     = false;

                    using (new ReadLock(_lock))
                    {
                        removed = this._activatedParts.TryGetValue(definition, out removedPart);
                    }
                    if (removed)
                    {
                        ReleasePart(null, removedPart, atomicComposition);
                        atomicComposition.AddCompleteActionAllowNull(() =>
                        {
                            using (new WriteLock(_lock))
                            {
                                this._activatedParts.Remove(definition);
                            }
                        });
                    }
                }

                UpdateRejections(addedExports.ConcatAllowingNull(removedExports), atomicComposition);

                this.OnExportsChanging(
                    new ExportsChangeEventArgs(addedExports, removedExports, atomicComposition));

                atomicComposition.AddCompleteAction(() => this.OnExportsChanged(
                                                        new ExportsChangeEventArgs(addedExports, removedExports, null)));

                atomicComposition.Complete();
            }
        }
示例#3
0
        private void ReleasePart(object exportedValue, ComposablePart part, AtomicComposition atomicComposition)
        {
            this.ThrowIfDisposed();
            this.EnsureRunning();

            Assumes.NotNull(part);

            this._importEngine.ReleaseImports(part, atomicComposition);

            if (exportedValue != null)
            {
                atomicComposition.AddCompleteActionAllowNull(() =>
                {
                    using (new WriteLock(this._lock))
                    {
                        this._conditionalReferencesForRecomposableParts.Remove(exportedValue);
                    }
                });
            }

            IDisposable diposablePart = part as IDisposable;

            if (diposablePart != null)
            {
                atomicComposition.AddCompleteActionAllowNull(() =>
                {
                    bool removed = false;
                    using (new WriteLock(this._lock))
                    {
                        removed = this._partsToDispose.Remove(diposablePart);
                    }
                    if (removed)
                    {
                        diposablePart.Dispose();
                    }
                });
            }
        }
        private void OnCatalogChanging(object sender, ComposablePartCatalogChangeEventArgs e)
        {
            using (var atomicComposition = new AtomicComposition(e.AtomicComposition))
            {
                // Save the preview catalog to use in place of the original while handling
                // this event
                atomicComposition.SetValue(_catalog,
                                           new CatalogChangeProxy(_catalog, e.AddedDefinitions, e.RemovedDefinitions));

                IEnumerable <ExportDefinition> addedExports   = GetExportsFromPartDefinitions(e.AddedDefinitions);
                IEnumerable <ExportDefinition> removedExports = GetExportsFromPartDefinitions(e.RemovedDefinitions);

                // Remove any parts based on eliminated definitions (in a atomicComposition-friendly
                // fashion)
                foreach (var definition in e.RemovedDefinitions)
                {
                    CatalogPart removedPart = null;
                    bool        removed     = false;

                    using (_lock.LockStateForRead())
                    {
                        removed = _activatedParts.TryGetValue(definition, out removedPart);
                    }

                    if (removed)
                    {
                        var capturedDefinition = definition;
                        DisposePart(null, removedPart, atomicComposition);
                        atomicComposition.AddCompleteActionAllowNull(() =>
                        {
                            using (_lock.LockStateForWrite())
                            {
                                _activatedParts.Remove(capturedDefinition);
                            }
                        });
                    }
                }

                UpdateRejections(addedExports.ConcatAllowingNull(removedExports), atomicComposition);

                OnExportsChanging(
                    new ExportsChangeEventArgs(addedExports, removedExports, atomicComposition));

                atomicComposition.AddCompleteAction(() => OnExportsChanged(
                                                        new ExportsChangeEventArgs(addedExports, removedExports, null)));

                atomicComposition.Complete();
            }
        }
        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);
        }
        private void DisposePart(object exportedValue, CatalogPart catalogPart, AtomicComposition atomicComposition)
        {
            Assumes.NotNull(catalogPart);

            if (_isDisposed)
            {
                return;
            }

            ImportEngine importEngine = null;

            using (_lock.LockStateForWrite())
            {
                if (_isDisposed)
                {
                    return;
                }

                importEngine = _importEngine;
            }
            if (importEngine != null)
            {
                importEngine.ReleaseImports(catalogPart.Part, atomicComposition);
            }
            if (exportedValue != null)
            {
                atomicComposition.AddCompleteActionAllowNull(() =>
                {
                    AllowPartCollection(exportedValue);
                });
            }

            IDisposable diposablePart = catalogPart.Part as IDisposable;

            if (diposablePart != null)
            {
                atomicComposition.AddCompleteActionAllowNull(() =>
                {
                    bool removed = false;

                    if (_isDisposed)
                    {
                        return;
                    }
                    using (_lock.LockStateForWrite())
                    {
                        if (_isDisposed)
                        {
                            return;
                        }

                        removed = _partsToDispose.Remove(diposablePart);
                    }

                    if (removed)
                    {
                        diposablePart.Dispose();
                    }
                });
            }
        }
示例#7
0
        private bool DetermineRejection(ComposablePartDefinition definition, AtomicComposition parentAtomicComposition)
        {
            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.
                UpdateAtomicCompositionQuery(localAtomicComposition,
                                             def => definition.Equals(def), AtomicCompositionQueryState.TreatAsValidated);

                var newPart = definition.CreatePart();
                try
                {
                    this._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 (new WriteLock(this._lock))
                        {
                            if (!this._activatedParts.ContainsKey(definition))
                            {
                                this._activatedParts.Add(definition, newPart);
                                IDisposable newDisposablePart = newPart as IDisposable;
                                if (newDisposablePart != null)
                                {
                                    this._partsToDispose.Add(newDisposablePart);
                                }
                            }
                        }
                    });

                    // Success! Complete any recursive work that was conditioned on this part's validation
                    localAtomicComposition.Complete();

                    return(false);
                }
                catch (ChangeRejectedException exception)
                {
                    // We should perhaps add non-debug tracing of these errors to help diagosis
                    // composition issues related to parts being rejected.
                    Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Part {0} was rejected because of the following issue:", newPart));
                    Debug.WriteLine(exception.Message);
                }
            }

            // If we've reached this point then this part has been rejected so we need to
            // record the rejection in our parent atomicComposition
            parentAtomicComposition.AddCompleteActionAllowNull(() =>
            {
                using (new WriteLock(this._lock))
                {
                    this._rejectedParts.Add(definition);
                }
            });
            if (parentAtomicComposition != null)
            {
                UpdateAtomicCompositionQuery(parentAtomicComposition,
                                             def => definition.Equals(def), AtomicCompositionQueryState.TreatAsRejected);
            }

            return(true);
        }