private async Task ExecuteStepAsync(RecipeExecutionContext 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 recipeStepHandlers = scope.ServiceProvider.GetRequiredService <IEnumerable <IRecipeStepHandler> >(); var scriptingManager = scope.ServiceProvider.GetRequiredService <IScriptingManager>(); scriptingManager.GlobalMethodProviders.Add(_environmentMethodProvider); // Substitutes the script elements by their actual values EvaluateScriptNodes(recipeStep, scriptingManager); foreach (var recipeStepHandler in recipeStepHandlers) { if (Logger.IsEnabled(LogLevel.Information)) { Logger.LogInformation("Executing recipe step '{0}'.", recipeStep.Name); } await _eventBus.NotifyAsync <IRecipeEventHandler>(e => e.RecipeStepExecutingAsync(recipeStep)); await recipeStepHandler.ExecuteAsync(recipeStep); await _eventBus.NotifyAsync <IRecipeEventHandler>(e => e.RecipeStepExecutedAsync(recipeStep)); if (Logger.IsEnabled(LogLevel.Information)) { Logger.LogInformation("Finished executing recipe step '{0}'.", recipeStep.Name); } } } // 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); } } }
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); } } } }
private void DoWork(object group) { // DoWork is not re-entrant as Timer will not call the callback until the previous callback has returned. // This way if a tasks takes longer than the period itself, DoWork is not called while it's still running. ShellContext shellContext = _orchardHost.GetOrCreateShellContext(_shellSettings); var groupName = group as string ?? ""; foreach (var task in _tasks[groupName]) { var taskName = task.GetType().FullName; using (var scope = shellContext.CreateServiceScope()) { try { lock (_states) { _states[task] = BackgroundTaskState.Running; } if (Logger.IsEnabled(LogLevel.Information)) { Logger.LogInformation("Start processing background task \"{0}\".", taskName); } task.DoWork(scope.ServiceProvider, _applicationLifetime.ApplicationStopping); if (Logger.IsEnabled(LogLevel.Information)) { Logger.LogInformation("Finished processing background task \"{0}\".", taskName); } } catch (Exception ex) { if (Logger.IsEnabled(LogLevel.Error)) { Logger.LogError($"Error while processing background task \"{taskName}\": {ex.Message}"); } } finally { lock (_states) { _states[task] = BackgroundTaskState.Idle; } } } } }
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.Set(shellSetting); // We only serve the next request if the tenant has been resolved. if (shellSetting != null) { var shellContext = _orchardHost.GetOrCreateShellContext(shellSetting); using (var scope = shellContext.CreateServiceScope()) { httpContext.RequestServices = scope.ServiceProvider; if (!shellContext.IsActivated) { lock (shellContext) { // The tenant gets activated here if (!shellContext.IsActivated) { var tenantEvents = scope.ServiceProvider .GetServices <IModularTenantEvents>(); foreach (var tenantEvent in tenantEvents) { tenantEvent.ActivatingAsync().Wait(); } httpContext.Items["BuildPipeline"] = true; shellContext.IsActivated = true; foreach (var tenantEvent in tenantEvents) { tenantEvent.ActivatedAsync().Wait(); } } } } await _next.Invoke(httpContext); } } }
public async Task <IActionResult> Create(EditTenantViewModel model) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageTenants)) { return(Unauthorized()); } if (!IsDefaultShell()) { return(Unauthorized()); } if (ModelState.IsValid) { ValidateViewModel(model, true); } if (ModelState.IsValid) { var shellSettings = new ShellSettings { Name = model.Name, RequestUrlPrefix = model.RequestUrlPrefix, RequestUrlHost = model.RequestUrlHost, ConnectionString = model.ConnectionString, TablePrefix = model.TablePrefix, DatabaseProvider = model.DatabaseProvider, State = TenantState.Uninitialized }; _shellSettingsManager.SaveSettings(shellSettings); var shellContext = _orchardHost.GetOrCreateShellContext(shellSettings); return(RedirectToAction(nameof(Index))); } // If we got this far, something failed, redisplay form return(View(model)); }
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); } } } }
public async Task <string> ExecuteAsync(string executionId, RecipeDescriptor recipeDescriptor) { await _eventBus.NotifyAsync <IRecipeEventHandler>(x => x.RecipeExecutingAsync(executionId, recipeDescriptor)); try { var parsersForFileExtension = _recipeOptions .RecipeFileExtensions .Where(rfx => Path.GetExtension(rfx.Key) == Path.GetExtension(recipeDescriptor.RecipeFileInfo.PhysicalPath)); using (var stream = recipeDescriptor.RecipeFileInfo.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; await _recipeStore.UpdateAsync(result); } using (var stream = recipeDescriptor.RecipeFileInfo.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; } }
public async Task <string> ExecuteAsync(string executionId, RecipeDescriptor recipeDescriptor) { await _eventBus.NotifyAsync <IRecipeEventHandler>(x => x.RecipeExecutingAsync(executionId, recipeDescriptor)); try { RecipeResult result = new RecipeResult { ExecutionId = executionId }; List <RecipeStepResult> stepResults = new List <RecipeStepResult>(); using (StreamReader file = File.OpenText(recipeDescriptor.RecipeFileInfo.PhysicalPath)) { using (var reader = new JsonTextReader(file)) { VariablesMethodProvider variablesMethodProvider = null; // Go to Steps, then iterate. while (reader.Read()) { if (reader.Path == "variables") { reader.Read(); var variables = JObject.Load(reader); variablesMethodProvider = new VariablesMethodProvider(variables); } if (reader.Path == "steps" && reader.TokenType == JsonToken.StartArray) { int stepId = 0; while (reader.Read() && reader.Depth > 1) { if (reader.Depth == 2) { var child = JToken.Load(reader); var recipeStep = new RecipeStepDescriptor { Id = (stepId++).ToString(), Name = child.Value <string>("name"), Step = child }; 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>(); var scriptingManager = scope.ServiceProvider.GetRequiredService <IScriptingManager>(); if (variablesMethodProvider != null) { variablesMethodProvider.ScriptingManager = scriptingManager; scriptingManager.GlobalMethodProviders.Add(variablesMethodProvider); } if (_applicationLifetime.ApplicationStopping.IsCancellationRequested) { throw new OrchardException(T["Recipe cancelled, application is restarting"]); } EvaluateJsonTree(scriptingManager, recipeStep.Step); 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 recipeStepExecutor = scope.ServiceProvider.GetRequiredService <IRecipeStepExecutor>(); 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; } }