コード例 #1
0
        private void Execute(Entry entry)
        {
            // Force reloading extensions if there were extensions installed
            // See https://github.com/BoyingCMS/Boying/issues/1294
            if (entry.MessageName == "IRecipeSchedulerEventHandler.ExecuteWork")
            {
                var ctx = _BoyingHost().GetShellContext(entry.ShellSettings);
            }

            var shellContext = _shellContextFactory.CreateDescribedContext(entry.ShellSettings, entry.ShellDescriptor);

            using (shellContext.LifetimeScope)
            {
                using (var standaloneEnvironment = shellContext.LifetimeScope.CreateWorkContextScope())
                {
                    ITransactionManager transactionManager;
                    if (!standaloneEnvironment.TryResolve(out transactionManager))
                    {
                        transactionManager = null;
                    }

                    try
                    {
                        var eventBus = standaloneEnvironment.Resolve <IEventBus>();
                        Logger.Information("Executing event {0} in process {1} for shell {2}",
                                           entry.MessageName,
                                           entry.ProcessId,
                                           entry.ShellSettings.Name);
                        eventBus.Notify(entry.MessageName, entry.EventData);
                    }
                    catch
                    {
                        // any database changes in this using(env) scope are invalidated
                        if (transactionManager != null)
                        {
                            transactionManager.Cancel();
                        }
                        throw;
                    }
                }
            }
        }
コード例 #2
0
        async Task <ConcurrentDictionary <string, IFeatureEventContext> > InvokeFeatureEventsAsync(
            IList <IShellFeature> features,
            Func <IFeatureEventContext, IFeatureEventHandler, Task <ConcurrentDictionary <string, IFeatureEventContext> > > handler,
            Func <IFeatureEventContext, Task <ConcurrentDictionary <string, IFeatureEventContext> > > noHandler)
        {
            // Holds the results of all our event execution contexts
            var contexts = new ConcurrentDictionary <string, IFeatureEventContext>();

            // Build a list of all unique features we are enabling / disabling
            var uniqueFeatures = new ConcurrentDictionary <string, IShellFeature>();

            foreach (var feature in features)
            {
                // The feature may also reference dependencies so ensure we also
                // add any dependencies for the features to our temporary shell descriptors
                if (feature.FeatureDependencies.Any())
                {
                    foreach (var dependency in feature.FeatureDependencies)
                    {
                        if (!uniqueFeatures.ContainsKey(dependency.ModuleId))
                        {
                            uniqueFeatures.TryAdd(dependency.ModuleId, dependency);
                        }
                    }
                }
                if (!uniqueFeatures.ContainsKey(feature.ModuleId))
                {
                    uniqueFeatures.TryAdd(feature.ModuleId, feature);
                }
            }

            // Ensure minimum features are always available within the temporary shell descriptor
            // We may depend upon services from the required features within the features we are enabling / disabling
            var minimumShellDescriptor = _shellContextFactory.MinimumShellDescriptor();

            // Add features and dependencies we are enabling / disabling to our minimum shell descriptor
            foreach (var feature in uniqueFeatures.Values)
            {
                minimumShellDescriptor.Modules.Add(new ShellModule(feature.ModuleId, feature.Version));
            }

            // Create a new shell context with features and all dependencies we need to enable / disable
            using (var shellContext = _shellContextFactory.CreateDescribedContext(_shellSettings, minimumShellDescriptor))
            {
                using (var scope = shellContext.ServiceProvider.CreateScope())
                {
                    var handlers     = scope.ServiceProvider.GetServices <IFeatureEventHandler>();
                    var handlersList = handlers.ToList();

                    // Iterate through each feature we wish to invoke
                    // Use the event handlers if available else just add to contexts collection
                    foreach (var feature in features)
                    {
                        // Only invoke non required features
                        if (feature.IsRequired)
                        {
                            continue;
                        }

                        // Context that will be passed around
                        var context = new FeatureEventContext()
                        {
                            Feature         = feature,
                            ServiceProvider = scope.ServiceProvider,
                            Logger          = _logger
                        };

                        // Get event handler for feature we are invoking
                        var featureHandler = handlersList.FirstOrDefault(h => h.ModuleId == feature.ModuleId);

                        // Get response from responsible func
                        var handlerContexts = featureHandler != null
                            ? await handler(context, featureHandler)
                            : await noHandler(context);

                        // Compile results from delegates
                        if (handlerContexts != null)
                        {
                            foreach (var handlerContext in handlerContexts)
                            {
                                contexts.AddOrUpdate(feature.ModuleId, handlerContext.Value, (k, v) =>
                                {
                                    foreach (var error in handlerContext.Value.Errors)
                                    {
                                        v.Errors.Add(error.Key, error.Value);
                                    }

                                    return(v);
                                });
                            }
                        }

                        // Log any errors
                        if (context.Errors.Count > 0)
                        {
                            foreach (var error in context.Errors)
                            {
                                _logger.LogCritical(error.Value,
                                                    $"An error occurred whilst invoking within {this.GetType().FullName}");
                            }
                        }
                    }
                }
            }

            return(contexts);
        }
コード例 #3
0
        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.Cms",
                "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);

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

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

                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())
                {
                    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)
                    {
                        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);
        }