public async Task <IActionResult> ContinueExecutionAsync([Required] string executionId, [Required, FromBody] ContinueExecutionApiModel continueApiModel) { // Build the execution request context so we can pick up where we left off... var erContext = new ExecutionRequestContext <ContinueExecutionApiModel>(continueApiModel) { Execution = await execRepository.GetExecutionAsync(executionId, userContext.Executor.TenantId) }; // If we can't find the original execution, respond with [404 Not Found]... if (erContext.Execution == null) { return(NotFound($"[{ErrorCodes.ExecutionNotFound}]: Execution [{executionId}] not found.")); } // If we found the execution but we're not expecting any input objects, respond with [400 Bad Request]... if (erContext.Execution.Status != ExecutionStatus.PendingInputObjects) { return(BadRequest($"[{ErrorCodes.UnableToContinue}]: Unable to continue; " + $"execution [{executionId}] is already [{erContext.Execution.Status}].")); } // Augment the execution request context with extension, extension version, and execution profile. // We're going to need all of this information to build and dispatch the core execution request... erContext.Extension = await extensionRepository.GetExtensionAsync(erContext.Execution.ExtensionId); erContext.ExtensionVersion = erContext.Extension.GetExtensionVersion(erContext.Execution.ExtensionVersionId); erContext.ExecutionProfile = erContext.ExtensionVersion.GetExecutionProfile(erContext.Execution.ExecutionProfileName); // Make sure that we have the right input objects and only the right input objects... erContext.Execution.ProvidedInputObjects.AddRange(erContext.OriginalRequest.ProvidedInputObjects.Where(pio => erContext.ExtensionVersion.InputObjects.Any(io => io.Name == pio) && erContext.Execution.ProvidedInputObjects.Contains(pio) == false)); var unknownObjects = erContext.OriginalRequest.ProvidedInputObjects .Where(pio => erContext.Execution.InputObjects.Select(io => io.Name).Contains(pio) == false) .ToArray(); var neededObjects = erContext.Execution.InputObjects .Where(io => io.IsRequired && (erContext.OriginalRequest.ProvidedInputObjects.Contains(io.Name) == false)) .Select(io => io.Name) .ToArray(); // If we don't, respond with [400 Bad Request] + detailed error description... if (unknownObjects.Any() || neededObjects.Any()) { var errorMessages = new List <string>(); if (unknownObjects.Any()) { errorMessages.Add($"[{ErrorCodes.UnknownInputObjects}]: " + $"The following provided input objects are unknown: [{unknownObjects.ToCommaSeparatedString()}]."); } if (neededObjects.Any()) { errorMessages.Add($"[{ErrorCodes.MissingInputObjects}]: " + $"The following input objects are missing: [{neededObjects.ToCommaSeparatedString()}]."); } return(BadRequest(await CreateToContinueApiModelAsync(erContext, errorMessages.ToSpaceSeparatedString()))); } else { // Otherwise, dispatch the execution request to the execution pipeline and respond back to the client appropriately. // For more information on the execution pipeline, see /doc/architecture/execution-pipeline.md. return(await ToExecutionRequestRoutedResultAsync(await ExecuteAsync(erContext))); } }