public static async ValueTask <object?> EvaluateActivityPropertyValue(
            this IWorkflowBlueprint workflowBlueprint,
            string activityId,
            string propertyName,
            ActivityExecutionContext activityExecutionContext,
            CancellationToken cancellationToken)
        {
            var provider = workflowBlueprint.ActivityPropertyProviders.GetProvider(activityId, propertyName);
            var value    = provider != null ? await provider.GetValueAsync(activityExecutionContext, cancellationToken) : null;

            if (value == null)
            {
                // Get default value.
                var activityTypeService = activityExecutionContext.GetService <IActivityTypeService>();
                var activityBlueprint   = workflowBlueprint.GetActivity(activityId) !;
                var activityType        = await activityTypeService.GetActivityTypeAsync(activityBlueprint.Type, cancellationToken);

                var activityDescriptor = await activityTypeService.DescribeActivityType(activityType, cancellationToken);

                var propertyDescriptor = activityDescriptor.InputProperties.FirstOrDefault(x => x.Name == propertyName);

                value = propertyDescriptor?.DefaultValue;
            }

            return(value);
        }
        public virtual async Task <RunWorkflowResult> RunWorkflowAsync(
            IWorkflowBlueprint workflowBlueprint,
            WorkflowInstance workflowInstance,
            string?activityId = default,
            object?input      = default,
            CancellationToken cancellationToken = default)
        {
            using var loggingScope           = _logger.BeginScope(new Dictionary <string, object> { ["WorkflowInstanceId"] = workflowInstance.Id });
            using var workflowExecutionScope = _serviceScopeFactory.CreateScope();
            var workflowExecutionContext = new WorkflowExecutionContext(workflowExecutionScope.ServiceProvider, workflowBlueprint, workflowInstance, input);

            if (!string.IsNullOrWhiteSpace(workflowInstance.ContextId))
            {
                var loadContext = new LoadWorkflowContext(workflowExecutionContext);
                workflowExecutionContext.WorkflowContext = await _workflowContextManager.LoadContext(loadContext, cancellationToken);
            }

            // If the workflow instance has a CurrentActivity, it means the workflow instance is being retried.
            var currentActivity = workflowInstance.CurrentActivity;

            if (currentActivity != null)
            {
                activityId = currentActivity.ActivityId;
            }

            var activity = activityId != null?workflowBlueprint.GetActivity(activityId) : default;

            // Give application a chance to prevent workflow from executing.
            var validateWorkflowExecution = new ValidateWorkflowExecution(workflowExecutionContext, activity);
            await _mediator.Publish(validateWorkflowExecution, cancellationToken);

            if (!validateWorkflowExecution.CanExecuteWorkflow)
            {
                _logger.LogInformation("Workflow execution prevented for workflow {WorkflowInstanceId}", workflowInstance.Id);
                return(new RunWorkflowResult(workflowInstance, activityId, false));
            }

            await _mediator.Publish(new WorkflowExecuting(workflowExecutionContext), cancellationToken);

            RunWorkflowResult runWorkflowResult;

            switch (workflowExecutionContext.Status)
            {
            case WorkflowStatus.Idle:
                runWorkflowResult = await BeginWorkflow(workflowExecutionContext, activity, cancellationToken);

                if (!runWorkflowResult.Executed)
                {
                    _logger.LogDebug("Workflow {WorkflowInstanceId} cannot begin from an idle state (perhaps it needs a specific input)", workflowInstance.Id);
                    return(runWorkflowResult);
                }

                break;

            case WorkflowStatus.Running:
                await RunWorkflowAsync(workflowExecutionContext, cancellationToken);

                runWorkflowResult = new RunWorkflowResult(workflowInstance, activityId, true);
                break;

            case WorkflowStatus.Suspended:
                runWorkflowResult = await ResumeWorkflowAsync(workflowExecutionContext, activity !, cancellationToken);

                if (!runWorkflowResult.Executed)
                {
                    _logger.LogDebug("Workflow {WorkflowInstanceId} cannot be resumed from a suspended state (perhaps it needs a specific input)", workflowInstance.Id);
                    return(runWorkflowResult);
                }

                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            await _mediator.Publish(new WorkflowExecuted(workflowExecutionContext), cancellationToken);

            var statusEvent = workflowExecutionContext.Status switch
            {
                WorkflowStatus.Cancelled => new WorkflowCancelled(workflowExecutionContext),
                WorkflowStatus.Finished => new WorkflowCompleted(workflowExecutionContext),
                WorkflowStatus.Faulted => new WorkflowFaulted(workflowExecutionContext),
                WorkflowStatus.Suspended => new WorkflowSuspended(workflowExecutionContext),
                _ => default(INotification)
            };

            if (statusEvent != null)
            {
                _logger.LogTrace("Publishing a status event of type {EventType} for workflow {WorkflowInstanceId}", statusEvent.GetType().Name, workflowInstance.Id);
                await _mediator.Publish(statusEvent, cancellationToken);
            }

            await _mediator.Publish(new WorkflowExecutionFinished(workflowExecutionContext), cancellationToken);

            return(runWorkflowResult);
        }