using MainShell.Common; using MainShell.ProcessResult; using MW.WorkFlow; using System; using System.Threading.Tasks; namespace MainShell.Process { public abstract class ActivityAbstractBase : IActivity { public string Name { get; protected set; } protected ProcessResultManager ResultManager { get; private set; } protected string CurrentWorkflowName { get; private set; } = "UnknownFlow"; protected string ParentActivityName { get; private set; } = string.Empty; protected ActivityAbstractBase(string name) { if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentException("Activity name cannot be null or whitespace.", nameof(name)); } Name = name; } public async Task ExecuteAsync(WorkflowContext context, ActivityControl activityControl) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (activityControl == null) { throw new ArgumentNullException(nameof(activityControl)); } var result = ActivityResult.Failure; var hasFaulted = false; try { if (context.TryGetData(WorkflowContextKeys.WorkflowName, out var flowName)) { CurrentWorkflowName = flowName; } if (context.TryGetData(WorkflowContextKeys.ParentActivityName, out var parentName)) { ParentActivityName = parentName; } else { ParentActivityName = string.Empty; } if (context.TryGetData(WorkflowContextKeys.ProcessResultManager, out var manager)) { ResultManager = manager; ResultManager.UpdateFlowState(CurrentWorkflowName, ParentActivityName, Name, ProcessExecutionStatus.Running, null); } PrepareExecute(context, activityControl); result = await OnExecuteAsync(context, activityControl); return result; } catch (OperationCanceledException) { ResultManager?.UpdateFlowState(CurrentWorkflowName, ParentActivityName, Name, ProcessExecutionStatus.Canceled, null); throw; } catch (Exception ex) { if (!HasWorkflowFailure(context)) { SetWorkflowFailure( context, MessageKey.ProcessStepFailedWithReason, new object[] { Name, ex.Message ?? string.Empty }); } var errorMsg = ResolveWorkflowFailureMessage(context); ResultManager?.UpdateFlowState(CurrentWorkflowName, ParentActivityName, Name, ProcessExecutionStatus.Faulted, errorMsg); hasFaulted = true; throw; } finally { AfterExecute(context, activityControl); if (ResultManager != null && !hasFaulted) { if (result == ActivityResult.Success) { ResultManager.UpdateFlowState(CurrentWorkflowName, ParentActivityName, Name, ProcessExecutionStatus.Completed, null); } else if (result == ActivityResult.Canceled) { ResultManager.UpdateFlowState(CurrentWorkflowName, ParentActivityName, Name, ProcessExecutionStatus.Canceled, null); } else { ResultManager.UpdateFlowState( CurrentWorkflowName, ParentActivityName, Name, ProcessExecutionStatus.Faulted, ResolveWorkflowFailureMessage(context)); } } } } protected ActivityResult Fail(WorkflowContext context, MessageKey failureMessageKey, object[] failureMessageArguments) { SetWorkflowFailure(context, failureMessageKey, failureMessageArguments); return ActivityResult.Failure; } protected void SetWorkflowFailure(WorkflowContext context, MessageKey failureMessageKey, object[] failureMessageArguments) { if (context == null) { throw new ArgumentNullException(nameof(context)); } var normalized = NormalizeFailureMessageArguments(failureMessageArguments); context.SetData(WorkflowContextKeys.WorkflowFailureMessageKey, failureMessageKey); context.SetData(WorkflowContextKeys.WorkflowFailureMessageArguments, normalized); context.SetData(WorkflowContextKeys.WorkflowFailureMessage, LanguageResourceHelper.Format(failureMessageKey, normalized)); } protected void SetWorkflowFailure(WorkflowContext context, string failureMessage) { if (context == null) { throw new ArgumentNullException(nameof(context)); } context.SetData(WorkflowContextKeys.WorkflowFailureMessageKey, MessageKey.None); context.SetData(WorkflowContextKeys.WorkflowFailureMessageArguments, null); context.SetData(WorkflowContextKeys.WorkflowFailureMessage, failureMessage ?? string.Empty); } protected bool HasWorkflowFailure(WorkflowContext context) { if (context.TryGetData(WorkflowContextKeys.WorkflowFailureMessageKey, out var failureMessageKey) && failureMessageKey > MessageKey.None) { return true; } return context.TryGetData(WorkflowContextKeys.WorkflowFailureMessage, out var failureMessage) && !string.IsNullOrWhiteSpace(failureMessage); } protected string ResolveWorkflowFailureMessage(WorkflowContext context) { if (context.TryGetData(WorkflowContextKeys.WorkflowFailureMessageKey, out var failureMessageKey) && failureMessageKey > MessageKey.None) { return LanguageResourceHelper.Format(failureMessageKey, GetWorkflowFailureMessageArguments(context)); } if (context.TryGetData(WorkflowContextKeys.WorkflowFailureMessage, out var failureMessage) && !string.IsNullOrWhiteSpace(failureMessage)) { return failureMessage; } return string.Empty; } protected object[] GetWorkflowFailureMessageArguments(WorkflowContext context) { if (context.TryGetData(WorkflowContextKeys.WorkflowFailureMessageArguments, out var failureMessageArguments) && failureMessageArguments != null) { return failureMessageArguments; } return Array.Empty(); } protected object[] NormalizeFailureMessageArguments(object[] failureMessageArguments) { return failureMessageArguments ?? Array.Empty(); } protected abstract Task OnExecuteAsync(WorkflowContext context, ActivityControl activityControl); protected virtual void PrepareExecute(WorkflowContext context, ActivityControl activityControl) { } protected virtual void AfterExecute(WorkflowContext context, ActivityControl activityControl) { } } }