private ShellContext CreateStandaloneEnvironment(string tenant) { // Retrieve settings for speficified tenant. var settingsList = _shellSettingsManager.LoadSettings(); if (settingsList.Any()) { var settings = settingsList.SingleOrDefault(s => string.Equals(s.Name, tenant, StringComparison.OrdinalIgnoreCase)); if (settings == null) { throw new OrchardCoreException(T("Tenant {0} does not exist", tenant)); } return(_orchardHost.CreateShellContext(settings)); } else { // In case of an uninitialized site (no default settings yet), we create a default settings instance. var settings = new ShellSettings { Name = ShellHelper.DefaultShellName, State = TenantState.Uninitialized }; return(_orchardHost.CreateShellContext(settings)); } }
public async Task Invoke(HttpContext httpContext) { var shellSetting = GetSettings(httpContext.Request.Host.Value); if (shellSetting != null) { using (var shell = _orchardHost.CreateShellContext(shellSetting)) { httpContext.RequestServices = shell.LifetimeScope; shell.Shell.Activate(); await _next.Invoke(httpContext); } } else { throw new Exception("Tenant not found"); } }
public async Task Invoke(HttpContext httpContext) { var sw = Stopwatch.StartNew(); var shellSetting = GetSettings(httpContext.Request.Host.Value); if (shellSetting != null) { using (var shell = _orchardHost.CreateShellContext(shellSetting)) { httpContext.RequestServices = shell.LifetimeScope; shell.Shell.Activate(); await _next.Invoke(httpContext); } } else { _logger.LogError("Tenant not found"); throw new Exception("Tenant not found"); } _logger.LogVerbose("Request took {0}ms", sw.ElapsedMilliseconds); }
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; _runningShellRouterTable.Remove(shellSettings.Name); _orchardHost.UpdateShellSettings(shellSettings); return(executionId); }
public string SetupInternal(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 = { // Framework "Orchard.Hosting", // Core "Settings" }; 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; } // TODO: Add Encryption Settings in // 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 environment = _orchardHost.CreateShellContext(shellSettings)) { using (var scope = environment.CreateServiceScope()) { executionId = CreateTenantData(context, environment); var store = scope.ServiceProvider.GetRequiredService <IStore>(); store.InitializeAsync(); // Create the "minimum shell descriptor" scope .ServiceProvider .GetService <IShellDescriptorManager>() .UpdateShellDescriptorAsync( 0, environment.Blueprint.Descriptor.Features, environment.Blueprint.Descriptor.Parameters).Wait(); } } shellSettings.State = TenantState.Running; _runningShellRouterTable.Remove(shellSettings.Name); _orchardHost.UpdateShellSettings(shellSettings); return(executionId); }
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>(); 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); } 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); } if (deferredTaskEngine != null && deferredTaskEngine.HasPendingTasks) { var taskContext = new DeferredTaskContext(scope.ServiceProvider); await deferredTaskEngine.ExecuteTasksAsync(taskContext); } } } shellSettings.State = TenantState.Running; _orchardHost.UpdateShellSettings(shellSettings); return(executionId); }
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); }
public string SetupInternal(SetupContext context) { string executionId; _logger.LogInformation("Running setup for tenant '{0}'.", _shellSettings.Name); // The vanilla Orchard distibution has the following features enabled. string[] hardcoded = { // Framework "Orchard.Hosting", // Core "Settings", // Test Modules "Orchard.Demo", "Orchard.Test1" }; 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); shellSettings.DatabaseProvider = context.DatabaseProvider; shellSettings.ConnectionString = context.DatabaseConnectionString; shellSettings.TablePrefix = context.DatabaseTablePrefix; //if (shellSettings.DataProviders.Any()) { // DataProvider provider = new DataProvider(); //shellSettings.DataProvider = context.DatabaseProvider; //shellSettings.DataConnectionString = context.DatabaseConnectionString; //shellSettings.DataTablePrefix = context.DatabaseTablePrefix; //} // TODO: Add Encryption Settings in var shellDescriptor = new ShellDescriptor { Features = context.EnabledFeatures.Select(name => new ShellFeature { Name = name }).ToList() }; // creating a standalone environment. // 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 using (var environment = _orchardHost.CreateShellContext(shellSettings)) { executionId = CreateTenantData(context, environment); using (var store = (IStore)environment.ServiceProvider.GetService(typeof(IStore))) { store.InitializeAsync(); } } shellSettings.State = TenantState.Running; _orchardHost.UpdateShellSettings(shellSettings); return(executionId); }