public CatalogExportProvider(ComposablePartCatalog catalog, CompositionOptions compositionOptions) { Requires.NotNull(catalog, nameof(catalog)); if (compositionOptions > (CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe | CompositionOptions.ExportCompositionService)) { throw new ArgumentOutOfRangeException(nameof(compositionOptions)); } _catalog = catalog; _compositionOptions = compositionOptions; var notifyCatalogChanged = _catalog as INotifyComposablePartCatalogChanged; if (notifyCatalogChanged != null) { notifyCatalogChanged.Changing += OnCatalogChanging; } CompositionScopeDefinition scopeDefinition = _catalog as CompositionScopeDefinition; if (scopeDefinition != null) { _innerExportProvider = new AggregateExportProvider(new ScopeManager(this, scopeDefinition), new InnerCatalogExportProvider(this)); } else { _innerExportProvider = new InnerCatalogExportProvider(this); } _lock = new CompositionLock(compositionOptions.HasFlag(CompositionOptions.IsThreadSafe)); _disableSilentRejection = compositionOptions.HasFlag(CompositionOptions.DisableSilentRejection); }
public static CompositionContainer RegisterCompositionService([NotNull] this Startup startup, [NotNull] IConfiguration configuration, [NotNull] string projectDirectory, [NotNull] Assembly callingAssembly, [NotNull, ItemNotNull] IEnumerable<string> additionalAssemblyFileNames, CompositionOptions options) { var toolsDirectory = configuration.GetString(Constants.Configuration.ToolsDirectory); if (options.HasFlag(CompositionOptions.AddWebsiteAssemblyResolver)) { // add an assembly resolver that points to the website/bin directory - this will load files like Sitecore.Kernel.dll AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => ResolveAssembly(args, configuration); } // add application assemblies var coreAssembly = typeof(Constants).Assembly; var catalogs = new List<ComposablePartCatalog> { new AssemblyCatalog(coreAssembly), new AssemblyCatalog(callingAssembly) }; var disableExtensions = configuration.GetBool("disable-extensions"); if (!disableExtensions && !options.HasFlag(CompositionOptions.DisableExtensions)) { // add additional assemblies - this is used in Sitecore.Pathfinder.Server to load assemblies from the /bin folder AddAdditionalAssemblies(catalogs, additionalAssemblyFileNames); // add assemblies from the tools directory AddFeatureAssemblies(catalogs, toolsDirectory); // add core extensions var coreExtensionsDirectory = Path.Combine(toolsDirectory, "files\\extensions"); var coreAssemblyFileName = Path.Combine(coreExtensionsDirectory, "Sitecore.Pathfinder.Core.Extensions.dll"); AddDynamicAssembly(catalogs, toolsDirectory, coreAssemblyFileName, coreExtensionsDirectory); AddAssembliesFromDirectory(catalogs, coreExtensionsDirectory); // add extension from [Project]/node_modules directory AddNodeModules(catalogs, coreAssemblyFileName, projectDirectory); // add projects extensions var projectExtensionsDirectory = configuration.GetString(Constants.Configuration.ProjectExtensionsDirectory); if (!string.IsNullOrEmpty(projectExtensionsDirectory)) { projectExtensionsDirectory = PathHelper.Combine(projectDirectory, projectExtensionsDirectory); var projectAssemblyFileName = Path.Combine(projectExtensionsDirectory, configuration.GetString(Constants.Configuration.ProjectExtensionsAssemblyFileName)); AddDynamicAssembly(catalogs, toolsDirectory, projectAssemblyFileName, projectExtensionsDirectory); AddAssembliesFromDirectory(catalogs, projectExtensionsDirectory); } } // build composition graph var exportProvider = new CatalogExportProvider(new AggregateCatalog(catalogs)); var compositionContainer = new CompositionContainer(exportProvider); exportProvider.SourceProvider = compositionContainer; // register the composition service itself for DI compositionContainer.ComposeExportedValue<ICompositionService>(compositionContainer); compositionContainer.ComposeExportedValue(configuration); return compositionContainer; }
public static ICompositionService RegisterCompositionService([NotNull] this Startup startup, [NotNull] IConfiguration configuration, [NotNull] string projectDirectory, [NotNull, ItemNotNull] IEnumerable <string> additionalAssemblyFileNames, CompositionOptions options) { var toolsDirectory = configuration.GetToolsDirectory(); // add application assemblies var coreAssembly = typeof(Constants).GetTypeInfo().Assembly; var assemblies = new List <Assembly> { coreAssembly, Assembly.GetEntryAssembly() }; var disableExtensions = configuration.GetBool(Constants.Configuration.Extensions.Disabled); if (!disableExtensions && !options.HasFlag(CompositionOptions.DisableExtensions)) { // add additional assemblies - this is used in Sitecore.Pathfinder.Server to load assemblies from the /bin folder AddAdditionalAssemblies(assemblies, additionalAssemblyFileNames); // add core extensions - must come before feature assemblies to ensure the correct Sitecore.Pathfinder.Core.Extensions.dll is loaded var coreExtensionsDirectory = Path.Combine(toolsDirectory, "files\\extensions"); AddAssembliesFromDirectory(options, assemblies, coreExtensionsDirectory); // add feature assemblies from the same directory as Sitecore.Pathfinder.Core var binDirectory = configuration.GetString(Constants.Configuration.BinDirectory); if (string.IsNullOrEmpty(binDirectory)) { binDirectory = Path.GetDirectoryName(coreAssembly.Location); } if (!string.IsNullOrEmpty(binDirectory)) { AddFeatureAssemblies(options, assemblies, binDirectory); } // add extension from [Project]/packages directory AddNugetPackages(configuration, options, assemblies, projectDirectory); // add extension from [Project]/node_modules directory AddNodeModules(configuration, options, assemblies, projectDirectory); // add projects extensions var projectExtensionsDirectory = configuration.GetString(Constants.Configuration.Extensions.Directory); if (!string.IsNullOrEmpty(projectExtensionsDirectory)) { projectExtensionsDirectory = PathHelper.Combine(projectDirectory, projectExtensionsDirectory); AddAssembliesFromDirectory(options, assemblies, projectExtensionsDirectory); } } var compositionHost = new ContainerConfiguration().WithProvider(new ConfigurationExportDescriptorProvider(configuration)).WithAssemblies(assemblies).CreateContainer(); // todo: breaks DI var compositionService = ((CompositionService)compositionHost.GetExport <ICompositionService>()).With(compositionHost); return(compositionService); }
public ImportEngine(ExportProvider sourceProvider, CompositionOptions compositionOptions) { Requires.NotNull(sourceProvider, "sourceProvider"); this._compositionOptions = compositionOptions; this._sourceProvider = sourceProvider; this._sourceProvider.ExportsChanging += this.OnExportsChanging; this._lock = new CompositionLock(compositionOptions.HasFlag(CompositionOptions.IsThreadSafe)); }
public ImportEngine(ExportProvider sourceProvider, CompositionOptions compositionOptions) { Requires.NotNull(sourceProvider, nameof(sourceProvider)); _compositionOptions = compositionOptions; _sourceProvider = sourceProvider; _sourceProvider.ExportsChanging += OnExportsChanging; _lock = new CompositionLock(compositionOptions.HasFlag(CompositionOptions.IsThreadSafe)); }
public ImportEngine(ExportProvider sourceProvider, CompositionOptions compositionOptions) { Requires.NotNull(sourceProvider, "sourceProvider"); this._compositionOptions = compositionOptions; this._sourceProvider = sourceProvider; this._sourceProvider.ExportsChanging += this.OnExportsChanging; this._lock = new CompositionLock(compositionOptions.HasFlag(CompositionOptions.IsThreadSafe)); }
public ComposablePartExportProvider(CompositionOptions compositionOptions) { if (compositionOptions > (CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe | CompositionOptions.ExportCompositionService)) { throw new ArgumentOutOfRangeException(nameof(compositionOptions)); } _compositionOptions = compositionOptions; _lock = new CompositionLock(compositionOptions.HasFlag(CompositionOptions.IsThreadSafe)); }
/// <summary> /// Previews all the required imports for the given <see cref="ComposablePart"/> to /// ensure they can all be satisified. The preview does not actually set the imports /// only ensures that they exist in the source provider. If the preview succeeds then /// the <see cref="ImportEngine"/> also enforces that changes to exports in the source /// provider will not break any of the required imports. If this enforcement needs to be /// lifted for this part then <see cref="ReleaseImports"/> needs to be called for this /// <see cref="ComposablePart"/>. /// </summary> /// <param name="part"> /// The <see cref="ComposablePart"/> to preview the required imports. /// </param> /// <param name="atomicComposition"></param> /// <exception cref="CompositionException"> /// An error occurred during previewing and <paramref name="atomicComposition"/> is null. /// <see cref="CompositionException.Errors"/> will contain a collection of errors that occurred. /// The pre-existing composition is in an unknown state, depending on the errors that occured. /// </exception> /// <exception cref="ChangeRejectedException"> /// An error occurred during the previewing and <paramref name="atomicComposition"/> is not null. /// <see cref="CompositionException.Errors"/> will contain a collection of errors that occurred. /// The pre-existing composition remains in valid state. /// </exception> /// <exception cref="ObjectDisposedException"> /// The <see cref="ImportEngine"/> has been disposed of. /// </exception> public void PreviewImports(ComposablePart part, AtomicComposition?atomicComposition) { ThrowIfDisposed(); Requires.NotNull(part, nameof(part)); // Do not do any previewing if SilentRejection is disabled. if (_compositionOptions.HasFlag(CompositionOptions.DisableSilentRejection)) { return; } // NOTE : this is a very intricate area threading-wise, please use caution when changing, otherwise state corruption or deadlocks will ensue // The gist of what we are doing is as follows: // We need to lock the composition, as we will proceed modifying our internal state. The tricky part is when we release the lock // Due to the fact that some actions will take place AFTER we leave this method, we need to KEEP THAT LOCK HELD until the transation is commiited or rolled back // This is the reason we CAN'T use "using here. // Instead, if the transaction is present we will queue up the release of the lock, otherwise we will release it when we exit this method // We add the "release" lock to BOTH Commit and Revert queues, because they are mutually exclusive, and we need to release the lock regardless. // This will take the lock, if necesary IDisposable?compositionLockHolder = _lock.IsThreadSafe ? _lock.LockComposition() : null; bool compositionLockTaken = (compositionLockHolder != null); try { // revert actions are processed in the reverse order, so we have to add the "release lock" action now if (compositionLockTaken && (atomicComposition != null)) { atomicComposition.AddRevertAction(() => compositionLockHolder !.Dispose()); } var partManager = GetPartManager(part, true) !; var result = TryPreviewImportsStateMachine(partManager, part, atomicComposition); result.ThrowOnErrors(atomicComposition); StartSatisfyingImports(partManager, atomicComposition); // Add the "release lock" to the commit actions if (compositionLockTaken && (atomicComposition != null)) { atomicComposition.AddCompleteAction(() => compositionLockHolder !.Dispose()); } } finally { // We haven't updated the queues, so we can release the lock now if (compositionLockTaken && (atomicComposition == null)) { compositionLockHolder !.Dispose(); } } }
/// <summary> /// Initializes a new instance of the <see cref="CompositionContainer"/> class /// with the specified catalog and export providers. /// </summary> /// <param name="compositionSettings"> /// <see cref="CompositionOptions"/> enumeration with flags controlling the composition. /// </param> /// <param name="providers"> /// A <see cref="Array"/> of <see cref="ExportProvider"/> objects which provide /// the <see cref="CompositionContainer"/> access to <see cref="Export"/> objects, /// or <see langword="null"/> to set <see cref="Providers"/> to an empty /// <see cref="ReadOnlyCollection{T}"/>. /// </param> /// <exception cref="ArgumentException"> /// <paramref name="providers"/> contains an element that is <see langword="null"/>. /// </exception> public CompositionContainer(ComposablePartCatalog catalog, CompositionOptions compositionOptions, params ExportProvider[] providers) { if (compositionOptions > (CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe | CompositionOptions.ExportCompositionService)) { throw new ArgumentOutOfRangeException("compositionOptions"); } this._compositionOptions = compositionOptions; this._partExportProvider = new ComposablePartExportProvider(compositionOptions); this._partExportProvider.SourceProvider = this; bool multiProvider = (catalog != null) || providers.Length > 0; if (multiProvider) { if (catalog != null) { this._catalogExportProvider = new CatalogExportProvider(catalog, compositionOptions); this._catalogExportProvider.SourceProvider = this; this._localExportProvider = new AggregateExportProvider(this._partExportProvider, this._catalogExportProvider); } else { this._localExportProvider = new AggregateExportProvider(this._partExportProvider); } if (providers != null && providers.Length > 0) { this._ancestorExportProvider = new AggregateExportProvider(providers); this._rootProvider = new AggregateExportProvider(this._localExportProvider, this._ancestorExportProvider); } else { this._rootProvider = this._localExportProvider; } } else { this._rootProvider = this._partExportProvider; } //Insert Composition Service if (compositionOptions.HasFlag(CompositionOptions.ExportCompositionService)) { this.ComposeExportedValue <ICompositionService>(new CompositionServiceShim(this)); } this._rootProvider.ExportsChanged += this.OnExportsChangedInternal; this._rootProvider.ExportsChanging += this.OnExportsChangingInternal; this._providers = (providers != null) ? new ReadOnlyCollection <ExportProvider>((ExportProvider[])providers.Clone()) : EmptyProviders; }
/// <summary> /// Initializes a new instance of the <see cref="CompositionContainer"/> class /// with the specified catalog and export providers. /// </summary> /// <param name="compositionSettings"> /// <see cref="CompositionOptions"/> enumeration with flags controlling the composition. /// </param> /// <param name="providers"> /// A <see cref="Array"/> of <see cref="ExportProvider"/> objects which provide /// the <see cref="CompositionContainer"/> access to <see cref="Export"/> objects, /// or <see langword="null"/> to set <see cref="Providers"/> to an empty /// <see cref="ReadOnlyCollection{T}"/>. /// </param> /// <exception cref="ArgumentException"> /// <paramref name="providers"/> contains an element that is <see langword="null"/>. /// </exception> public CompositionContainer(ComposablePartCatalog catalog, CompositionOptions compositionOptions, params ExportProvider[] providers) { if (compositionOptions > (CompositionOptions.DisableSilentRejection | CompositionOptions.IsThreadSafe | CompositionOptions.ExportCompositionService)) { throw new ArgumentOutOfRangeException("compositionOptions"); } _compositionOptions = compositionOptions; // We always create the mutable provider _partExportProvider = new ComposablePartExportProvider(compositionOptions); _partExportProvider.SourceProvider = this; // Create the catalog export provider, only if necessary if (catalog != null) { _catalogExportProvider = new CatalogExportProvider(catalog, compositionOptions); _catalogExportProvider.SourceProvider = this; } // Set the local export provider if (_catalogExportProvider != null) { _localExportProvider = new AggregateExportProvider(_partExportProvider, _catalogExportProvider); _disposableLocalExportProvider = _localExportProvider as IDisposable; } else { _localExportProvider = _partExportProvider; } // Set the ancestor export provider, if ancestors are supplied if ((providers != null) && (providers.Length > 0)) { // Aggregate ancestors if and only if more than one passed if (providers.Length > 1) { _ancestorExportProvider = new AggregateExportProvider(providers); _disposableAncestorExportProvider = _ancestorExportProvider as IDisposable; } else { if (providers[0] == null) { throw ExceptionBuilder.CreateContainsNullElement("providers"); } _ancestorExportProvider = providers[0]; } } // finally set the root provider if (_ancestorExportProvider == null) { // if no ancestors are passed, the local and the root are the same _rootProvider = _localExportProvider; } else { int exportProviderCount = 1 + ((catalog != null) ? 1 : 0) + ((providers != null) ? providers.Length : 0); ExportProvider[] rootProviders = new ExportProvider[exportProviderCount]; rootProviders[0] = _partExportProvider; int customProviderStartIndex = 1; if (catalog != null) { rootProviders[1] = _catalogExportProvider; customProviderStartIndex = 2; } if (providers != null) { for (int i = 0; i < providers.Length; i++) { rootProviders[customProviderStartIndex + i] = providers[i]; } } _rootProvider = new AggregateExportProvider(rootProviders); _disposableRootProvider = _rootProvider as IDisposable; } //Insert Composition Service if (compositionOptions.HasFlag(CompositionOptions.ExportCompositionService)) { this.ComposeExportedValue <ICompositionService>(new CompositionServiceShim(this)); } _rootProvider.ExportsChanged += OnExportsChangedInternal; _rootProvider.ExportsChanging += OnExportsChangingInternal; _providers = (providers != null) ? new ReadOnlyCollection <ExportProvider>((ExportProvider[])providers.Clone()) : EmptyProviders; }