コード例 #1
0
        public async Task Invoke(HttpContext httpContext)
        {
            // Ensure all ShellContext are loaded and available.
            _orchardHost.Initialize();

            var shellSetting = _runningShellTable.Match(httpContext);

            // Register the shell settings as a custom feature.
            httpContext.Features[typeof(ShellSettings)] = shellSetting;

            // We only serve the next request if the tenant has been resolved.
            if (shellSetting != null)
            {
                ShellContext shellContext = _orchardHost.GetOrCreateShellContext(shellSetting);

                using (var scope = shellContext.CreateServiceScope())
                {
                    httpContext.RequestServices = scope.ServiceProvider;

                    if (!shellContext.IsActivated)
                    {
                        lock (shellSetting)
                        {
                            // The tenant gets activated here
                            if (!shellContext.IsActivated)
                            {
                                var eventBus = scope.ServiceProvider.GetService<IEventBus>();
                                eventBus.NotifyAsync<IOrchardShellEvents>(x => x.ActivatingAsync()).Wait();
                                eventBus.NotifyAsync<IOrchardShellEvents>(x => x.ActivatedAsync()).Wait();

                                shellContext.IsActivated = true;
                            }
                        }
                    }

                    await _next.Invoke(httpContext);
                }

                using (var scope = shellContext.CreateServiceScope())
                {
                    var deferredTaskEngine = scope.ServiceProvider.GetService<IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var context = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(context);
                    }
                }
            }
        }
コード例 #2
0
        public async Task ExecuteTasksAsync(DeferredTaskContext context)
        {
            for (var i = 0; i < _deferredTaskState.Tasks.Count; i++)
            {
                var task = _deferredTaskState.Tasks[i];

                try
                {
                    await task(context);
                }
                catch (Exception e)
                {
                    _logger.LogError("An error occured while processing a deferred task: {0}", e);
                }
            }

            _deferredTaskState.Tasks.Clear();
        }
コード例 #3
0
        public async Task ExecuteTasksAsync(DeferredTaskContext context)
        {
            for(var i=0; i < _deferredTaskState.Tasks.Count; i++)
            {
                var task = _deferredTaskState.Tasks[i];

                try
                {
                    await task(context);
                }
                catch(Exception e)
                {
                    _logger.LogError("An error occured while processing a deferred task: {0}", e);
                }
            }

            _deferredTaskState.Tasks.Clear();
        }
        public async Task Invoke(HttpContext httpContext)
        {
            await _next.Invoke(httpContext);

            // Register the shell settings as a custom feature.
            var shellSettings = httpContext.Features[typeof(ShellSettings)] as ShellSettings;

            // We only serve the next request if the tenant has been resolved.
            if (shellSettings != null)
            {
                ShellContext shellContext = _orchardHost.GetOrCreateShellContext(shellSettings);

                using (var scope = shellContext.CreateServiceScope())
                {
                    var deferredTaskEngine = scope.ServiceProvider.GetService <IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var context = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(context);
                    }
                }
            }
        }
コード例 #5
0
ファイル: SetupService.cs プロジェクト: jchenga/Orchard2
        public async Task<string> SetupInternalAsync(SetupContext context)
        {
            string executionId;

            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Running setup for tenant '{0}'.", _shellSettings.Name);
            }

            // Features to enable for Setup
            string[] hardcoded =
            {
                "Orchard.Hosting", // shortcut for built-in features
                "Orchard.Modules",
                "Orchard.Recipes"
            };

            context.EnabledFeatures = hardcoded.Union(context.EnabledFeatures ?? Enumerable.Empty<string>()).Distinct().ToList();

            // Set shell state to "Initializing" so that subsequent HTTP requests are responded to with "Service Unavailable" while Orchard is setting up.
            _shellSettings.State = TenantState.Initializing;

            var shellSettings = new ShellSettings(_shellSettings);

            if (string.IsNullOrEmpty(shellSettings.DatabaseProvider))
            {
                shellSettings.DatabaseProvider = context.DatabaseProvider;
                shellSettings.ConnectionString = context.DatabaseConnectionString;
                shellSettings.TablePrefix = context.DatabaseTablePrefix;
            }

            // Creating a standalone environment based on a "minimum shell descriptor".
            // In theory this environment can be used to resolve any normal components by interface, and those
            // components will exist entirely in isolation - no crossover between the safemode container currently in effect
            // It is used to initialize the database before the recipe is run.

            var shellDescriptor = new ShellDescriptor
            {
                Features = context.EnabledFeatures.Select(name => new ShellFeature { Name = name }).ToList()
            };

            using (var shellContext = _shellContextFactory.CreateDescribedContext(shellSettings, shellDescriptor))
            {
                using (var scope = shellContext.CreateServiceScope())
                {
                    var store = scope.ServiceProvider.GetRequiredService<IStore>();

                    try
                    {
                        await store.InitializeAsync();
                    }
                    catch
                    {
                        // Tables already exist or database was not found

                        // The issue is that the user creation needs the tables to be present,
                        // if the user information is not valid, the next POST will try to recreate the
                        // tables. The tables should be rollbacked if one of the steps is invalid,
                        // unless the recipe is executing?
                    }

                    // Create the "minimum shell descriptor"
                    await scope
                        .ServiceProvider
                        .GetService<IShellDescriptorManager>()
                        .UpdateShellDescriptorAsync(0,
                            shellContext.Blueprint.Descriptor.Features,
                            shellContext.Blueprint.Descriptor.Parameters);

                    // Apply all migrations for the newly initialized tenant
                    var dataMigrationManager = scope.ServiceProvider.GetService<IDataMigrationManager>();
                    await dataMigrationManager.UpdateAllFeaturesAsync();

                    var deferredTaskEngine = scope.ServiceProvider.GetService<IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                    }
                }

                _orchardHost.UpdateShellSettings(shellSettings);

                executionId = Guid.NewGuid().ToString("n");

                // Create a new scope for the recipe thread to prevent race issues with other scoped
                // services from the request.
                using (var scope = shellContext.CreateServiceScope())
                {
                    var recipeExecutor = scope.ServiceProvider.GetService<IRecipeExecutor>();

                    // Right now we run the recipe in the same thread, later use polling from the setup screen
                    // to query the current execution.
                    //await Task.Run(async () =>
                    //{
                    await recipeExecutor.ExecuteAsync(executionId, context.Recipe);
                    //});

                }
            }

            // Reloading the shell context as the recipe  has probably updated its features
            using (var shellContext = _orchardHost.CreateShellContext(shellSettings))
            {
                using (var scope = shellContext.CreateServiceScope())
                {
                    // Apply all migrations for the newly initialized tenant
                    var dataMigrationManager = scope.ServiceProvider.GetService<IDataMigrationManager>();
                    await dataMigrationManager.UpdateAllFeaturesAsync();

                    bool hasErrors = false;

                    Action<string, string> reportError = (key, message) => {
                        hasErrors = true;
                        context.Errors[key] = message;
                    };

                    // Invoke modules to react to the setup event
                    var eventBus = scope.ServiceProvider.GetService<IEventBus>();
                    await eventBus.NotifyAsync<ISetupEventHandler>(x => x.Setup(
                        context.SiteName,
                        context.AdminUsername,
                        context.AdminEmail,
                        context.AdminPassword,
                        context.DatabaseProvider,
                        context.DatabaseConnectionString,
                        context.DatabaseTablePrefix,
                        reportError
                    ));

                    if (hasErrors)
                    {
                        // TODO: check why the tables creation is not reverted
                        var session = scope.ServiceProvider.GetService<YesSql.Core.Services.ISession>();
                        session.Cancel();

                        return executionId;
                    }

                    var deferredTaskEngine = scope.ServiceProvider.GetService<IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                    }
                }

                // Update the shell state
                shellSettings.State = TenantState.Running;
                _orchardHost.UpdateShellSettings(shellSettings);
            }


            return executionId;
        }
コード例 #6
0
ファイル: RecipeExecutor.cs プロジェクト: jchenga/Orchard2
        public async Task<string> ExecuteAsync(string executionId, RecipeDescriptor recipeDescriptor)
        {
            await _eventBus.NotifyAsync<IRecipeEventHandler>(x => x.RecipeExecutingAsync(executionId, recipeDescriptor));

            try
            {
                var fileInfo = _fileSystem.GetFileInfo(recipeDescriptor.Location);

                var parsersForFileExtension = _recipeOptions
                    .RecipeFileExtensions
                    .Where(rfx => Path.GetExtension(rfx.Key) == Path.GetExtension(fileInfo.PhysicalPath));

                using (var stream = fileInfo.CreateReadStream())
                {
                    RecipeResult result = new RecipeResult { ExecutionId = executionId };
                    List<RecipeStepResult> stepResults = new List<RecipeStepResult>();

                    foreach (var parserForFileExtension in parsersForFileExtension)
                    {
                        var recipeParser = _recipeParsers.First(x => x.GetType() == parserForFileExtension.Value);

                        await recipeParser.ProcessRecipeAsync(stream, (recipe, recipeStep) =>
                        {
                            // TODO, create Result prior to run
                            stepResults.Add(new RecipeStepResult
                            {
                                ExecutionId = executionId,
                                RecipeName = recipeDescriptor.Name,
                                StepId = recipeStep.Id,
                                StepName = recipeStep.Name
                            });
                            return Task.CompletedTask;
                        });
                    }

                    result.Steps = stepResults;
                    _session.Save(result);
                }

                using (var stream = fileInfo.CreateReadStream())
                {
                    foreach (var parserForFileExtension in parsersForFileExtension)
                    {
                        var recipeParser = _recipeParsers.First(x => x.GetType() == parserForFileExtension.Value);

                        await recipeParser.ProcessRecipeAsync(stream, async (recipe, recipeStep) =>
                        {
                            var shellContext = _orchardHost.GetOrCreateShellContext(_shellSettings);
                            using (var scope = shellContext.CreateServiceScope())
                            {
                                if (!shellContext.IsActivated)
                                {
                                    var eventBus = scope.ServiceProvider.GetService<IEventBus>();
                                    await eventBus.NotifyAsync<IOrchardShellEvents>(x => x.ActivatingAsync());
                                    await eventBus.NotifyAsync<IOrchardShellEvents>(x => x.ActivatedAsync());

                                    shellContext.IsActivated = true;
                                }

                                var recipeStepExecutor = scope.ServiceProvider.GetRequiredService<IRecipeStepExecutor>();

                                if (_applicationLifetime.ApplicationStopping.IsCancellationRequested)
                                {
                                    throw new OrchardException(T["Recipe cancelled, application is restarting"]);
                                }

                                await recipeStepExecutor.ExecuteAsync(executionId, recipeStep);
                            }

                            // The recipe execution might have invalidated the shell by enabling new features,
                            // so the deferred tasks need to run on an updated shell context if necessary.
                            shellContext = _orchardHost.GetOrCreateShellContext(_shellSettings);
                            using (var scope = shellContext.CreateServiceScope())
                            {
                                var deferredTaskEngine = scope.ServiceProvider.GetService<IDeferredTaskEngine>();

                                // The recipe might have added some deferred tasks to process
                                if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                                {
                                    var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                                    await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                                }
                            }
                        });
                    }
                }

                await _eventBus.NotifyAsync<IRecipeEventHandler>(x => x.RecipeExecutedAsync(executionId, recipeDescriptor));

                return executionId;
            }
            catch (Exception)
            {
                await _eventBus.NotifyAsync<IRecipeEventHandler>(x => x.ExecutionFailedAsync(executionId, recipeDescriptor));

                throw;
            }
        }
コード例 #7
0
ファイル: SetupService.cs プロジェクト: rodpl/Orchard2
        public async Task<string> SetupInternalAsync(SetupContext context)
        {
            string executionId;

            if (_logger.IsEnabled(LogLevel.Information))
            {
                _logger.LogInformation("Running setup for tenant '{0}'.", _shellSettings.Name);
            }

            // Features to enable for Setup
            string[] hardcoded =
            {
                "Orchard.Hosting" // shortcut for built-in features
            };

            context.EnabledFeatures = hardcoded.Union(context.EnabledFeatures ?? Enumerable.Empty<string>()).Distinct().ToList();

            // Set shell state to "Initializing" so that subsequent HTTP requests are responded to with "Service Unavailable" while Orchard is setting up.
            _shellSettings.State = TenantState.Initializing;

            var shellSettings = new ShellSettings(_shellSettings);

            if (string.IsNullOrEmpty(shellSettings.DatabaseProvider))
            {
                shellSettings.DatabaseProvider = context.DatabaseProvider;
                shellSettings.ConnectionString = context.DatabaseConnectionString;
                shellSettings.TablePrefix = context.DatabaseTablePrefix;
            }

            // Creating a standalone environment based on a "minimum shell descriptor".
            // In theory this environment can be used to resolve any normal components by interface, and those
            // components will exist entirely in isolation - no crossover between the safemode container currently in effect
            // It is used to initialize the database before the recipe is run.

            using (var shellContext = _orchardHost.CreateShellContext(shellSettings))
            {
                using (var scope = shellContext.CreateServiceScope())
                {
                    executionId = CreateTenantData(context, shellContext);

                    var store = scope.ServiceProvider.GetRequiredService<IStore>();
                    await store.InitializeAsync();

                    // Create the "minimum shell descriptor"
                    await scope
                        .ServiceProvider
                        .GetService<IShellDescriptorManager>()
                        .UpdateShellDescriptorAsync(
                            0,
                            shellContext.Blueprint.Descriptor.Features,
                            shellContext.Blueprint.Descriptor.Parameters);

                   // Apply all migrations for the newly initialized tenant
                    var dataMigrationManager = scope.ServiceProvider.GetService<IDataMigrationManager>();
                    await dataMigrationManager.UpdateAllFeaturesAsync();

                    var deferredTaskEngine = scope.ServiceProvider.GetService<IDeferredTaskEngine>();

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                    }

                    // Invoke modules to react to the setup event
                    var eventBus = scope.ServiceProvider.GetService<IEventBus>();
                    await eventBus.NotifyAsync<ISetupEventHandler>(x => x.Setup(
                        context.SiteName,
                        context.AdminUsername,
                        context.AdminEmail,
                        context.AdminPassword,
                        context.DatabaseProvider,
                        context.DatabaseConnectionString,
                        context.DatabaseTablePrefix)
                    );

                    if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks)
                    {
                        var taskContext = new DeferredTaskContext(scope.ServiceProvider);
                        await deferredTaskEngine.ExecuteTasksAsync(taskContext);
                    }
                }
            }

            shellSettings.State = TenantState.Running;
            _orchardHost.UpdateShellSettings(shellSettings);
            return executionId;
        }