/// <summary> /// Creates an engine with the specified application state, configuration, and service provider. /// </summary> /// <param name="applicationState">The state of the application (or <c>null</c> for an empty application state).</param> /// <param name="serviceCollection">The service collection (or <c>null</c> for an empty default service collection).</param> /// <param name="configuration">The application configuration.</param> /// <param name="settings">Settings that should override configuration values.</param> /// <param name="classCatalog">A class catalog of all assemblies in scope.</param> public Engine( ApplicationState applicationState, IServiceCollection serviceCollection, IConfiguration configuration, IEnumerable <KeyValuePair <string, object> > settings, ClassCatalog classCatalog) { _pipelines = new PipelineCollection(this); ApplicationState = applicationState ?? new ApplicationState(null, null, null); ClassCatalog = classCatalog ?? new ClassCatalog(); ClassCatalog.Populate(); ScriptHelper = new ScriptHelper(this); Settings = new ConfigurationSettings( this, configuration ?? new ConfigurationRoot(Array.Empty <IConfigurationProvider>()), settings); _serviceScope = GetServiceScope(serviceCollection); _logger = Services.GetRequiredService <ILogger <Engine> >(); DocumentFactory = new DocumentFactory(this, Settings); _diagnosticsTraceListener = new DiagnosticsTraceListener(_logger); System.Diagnostics.Trace.Listeners.Add(_diagnosticsTraceListener); // Add the service-based pipelines as late as possible so other services have been configured AddServicePipelines(); }
/// <summary> /// Creates an engine with the specified application state and service provider. /// </summary> /// <param name="applicationState">The state of the application (or <c>null</c> for an empty application state).</param> /// <param name="configuration">The application configuration.</param> /// <param name="serviceCollection">The service collection (or <c>null</c> for an empty default service collection).</param> public Engine(ApplicationState applicationState, IConfiguration configuration, IServiceCollection serviceCollection) { _pipelines = new PipelineCollection(this); ApplicationState = applicationState ?? new ApplicationState(null, null, null); Settings = new EngineSettings(configuration ?? new ConfigurationRoot(Array.Empty <IConfigurationProvider>())); _serviceScope = GetServiceScope(serviceCollection); _logger = Services.GetRequiredService <ILogger <Engine> >(); DocumentFactory = new DocumentFactory(Settings); _diagnosticsTraceListener = new DiagnosticsTraceListener(_logger); System.Diagnostics.Trace.Listeners.Add(_diagnosticsTraceListener); }
/// <summary> /// Creates an engine with the specified application state, configuration, and service provider. /// </summary> /// <param name="applicationState">The state of the application (or <c>null</c> for an empty application state).</param> /// <param name="serviceCollection">The service collection (or <c>null</c> for an empty default service collection).</param> /// <param name="configurationOverrides">Values that should override configuration values.</param> /// <param name="configuration">The application configuration.</param> public Engine(ApplicationState applicationState, IServiceCollection serviceCollection, IConfiguration configuration, IDictionary <string, object> configurationOverrides) { _pipelines = new PipelineCollection(this); ApplicationState = applicationState ?? new ApplicationState(null, null, null); ScriptHelper = new ScriptHelper(this); Settings = new ReadOnlyConfigurationSettings( this, configuration ?? new ConfigurationRoot(Array.Empty <IConfigurationProvider>()), configurationOverrides); _serviceScope = GetServiceScope(serviceCollection); _logger = Services.GetRequiredService <ILogger <Engine> >(); DocumentFactory = new DocumentFactory(this, Settings); _diagnosticsTraceListener = new DiagnosticsTraceListener(_logger); System.Diagnostics.Trace.Listeners.Add(_diagnosticsTraceListener); // Add the service-based pipelines as late as possible so other services have been configured AddServicePipelines(); }
// The result array is sorted based on dependencies private static PipelinePhase[] GetPipelinePhases(PipelineCollection pipelines, ILogger logger) { // Perform a topological sort to create phases down the dependency tree Dictionary <string, PipelinePhases> phases = new Dictionary <string, PipelinePhases>(StringComparer.OrdinalIgnoreCase); List <PipelinePhases> sortedPhases = new List <PipelinePhases>(); HashSet <string> visited = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair <string, IPipeline> pipelineEntry in pipelines) { Visit(pipelineEntry.Key, pipelineEntry.Value); } // Make a pass through non-isolated transform phases to set dependencies to all non-isolated process phases foreach (PipelinePhases pipelinePhases in phases.Values.Where(x => !x.Isolated)) { pipelinePhases.Transform.Dependencies = pipelinePhases.Transform.Dependencies .Concat(phases.Values.Where(x => x != pipelinePhases && !x.Isolated).Select(x => x.Process)) .ToArray(); } return(sortedPhases .Select(x => x.Input) .Concat(sortedPhases.Select(x => x.Process)) .Concat(sortedPhases.Select(x => x.Transform)) .Concat(sortedPhases.Select(x => x.Output)) .ToArray()); // Returns the process phases (if not isolated) PipelinePhases Visit(string name, IPipeline pipeline) { PipelinePhases pipelinePhases; if (pipeline.Isolated) { // This is an isolated pipeline so just add the phases in a chain pipelinePhases = new PipelinePhases(true); pipelinePhases.Input = new PipelinePhase(pipeline, name, Phase.Input, pipeline.InputModules, logger); pipelinePhases.Process = new PipelinePhase(pipeline, name, Phase.Process, pipeline.ProcessModules, logger, pipelinePhases.Input); pipelinePhases.Transform = new PipelinePhase(pipeline, name, Phase.Transform, pipeline.TransformModules, logger, pipelinePhases.Process); pipelinePhases.Output = new PipelinePhase(pipeline, name, Phase.Output, pipeline.OutputModules, logger, pipelinePhases.Transform); phases.Add(name, pipelinePhases); sortedPhases.Add(pipelinePhases); return(pipelinePhases); } if (visited.Add(name)) { // Visit dependencies if this isn't an isolated pipeline List <PipelinePhase> processDependencies = new List <PipelinePhase>(); foreach (string dependencyName in pipeline.Dependencies) { if (!pipelines.TryGetValue(dependencyName, out IPipeline dependency)) { throw new Exception($"Could not find pipeline dependency {dependencyName} of {name}"); } if (dependency.Isolated) { throw new Exception($"Pipeline {name} has dependency on isolated pipeline {dependencyName}"); } processDependencies.Add(Visit(dependencyName, dependency).Process); } // Add the phases (by this time all dependencies should have been added) pipelinePhases = new PipelinePhases(false); pipelinePhases.Input = new PipelinePhase(pipeline, name, Phase.Input, pipeline.InputModules, logger); processDependencies.Insert(0, pipelinePhases.Input); // Makes sure the process phase is also dependent on it's input phase pipelinePhases.Process = new PipelinePhase(pipeline, name, Phase.Process, pipeline.ProcessModules, logger, processDependencies.ToArray()); pipelinePhases.Transform = new PipelinePhase(pipeline, name, Phase.Transform, pipeline.TransformModules, logger, pipelinePhases.Process); // Transform dependencies will be added after all pipelines have been processed pipelinePhases.Output = new PipelinePhase(pipeline, name, Phase.Output, pipeline.OutputModules, logger, pipelinePhases.Transform); phases.Add(name, pipelinePhases); sortedPhases.Add(pipelinePhases); } else if (!phases.TryGetValue(name, out pipelinePhases)) { throw new Exception($"Pipeline cyclical dependency detected involving {name}"); } return(pipelinePhases); } }