274 lines
10 KiB
C#
274 lines
10 KiB
C#
using MainShell.Common;
|
||
using MainShell.ProcessResult;
|
||
using MW.WorkFlow;
|
||
using Stylet;
|
||
using System;
|
||
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace MainShell.Process
|
||
{
|
||
public class WorkflowRunCompletedEventArgs : EventArgs
|
||
{
|
||
public WorkflowState FinalState { get; }
|
||
public string Error { get; }
|
||
public string FailureMessage { get; }
|
||
public MessageKey FailureMessageKey { get; }
|
||
public object[] FailureMessageArguments { get; }
|
||
|
||
public WorkflowRunCompletedEventArgs(WorkflowState finalState, string error, string failureMessage, MessageKey failureMessageKey, object[] failureMessageArguments)
|
||
{
|
||
FinalState = finalState;
|
||
Error = error;
|
||
FailureMessage = failureMessage;
|
||
FailureMessageKey = failureMessageKey;
|
||
FailureMessageArguments = failureMessageArguments ?? Array.Empty<object>();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 封装工作流的启动、停止和状态管理,用于手动流程的复用。
|
||
/// </summary>
|
||
public class
|
||
WorkflowRunner : PropertyChangedBase, IDisposable
|
||
{
|
||
private WorkflowEngine _workflowEngine;
|
||
private bool _isRunning;
|
||
|
||
/// <summary>
|
||
/// 流程是否正在运行
|
||
/// </summary>
|
||
public bool IsRunning
|
||
{
|
||
get { return _isRunning; }
|
||
private set { SetAndNotify(ref _isRunning, value); }
|
||
}
|
||
|
||
public event EventHandler<WorkflowRunCompletedEventArgs> RunCompleted;
|
||
|
||
/// <summary>
|
||
/// 运行单个 Activity(自动包装为单步工作流)
|
||
/// </summary>
|
||
public Task RunActivityAsync(IActivity activity, WorkflowContext context)
|
||
{
|
||
if (activity == null) throw new ArgumentNullException(nameof(activity));
|
||
|
||
// 自动构建单步工作流定义
|
||
var stepId = "SingleStep_" + Guid.NewGuid().ToString("N");
|
||
var step = new WorkflowStep(stepId, activity);
|
||
var definition = new WorkflowDefinition(stepId);
|
||
definition.AddStep(step);
|
||
|
||
return RunAsync(definition, context);
|
||
}
|
||
|
||
public Task<WorkflowRunCompletedEventArgs> RunActivityWithResultAsync(IActivity activity, WorkflowContext context)
|
||
{
|
||
if (activity == null) throw new ArgumentNullException(nameof(activity));
|
||
|
||
var stepId = "SingleStep_" + Guid.NewGuid().ToString("N");
|
||
var step = new WorkflowStep(stepId, activity);
|
||
var definition = new WorkflowDefinition(stepId);
|
||
definition.AddStep(step);
|
||
|
||
return RunWithResultAsync(definition, context, null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 运行完整的工作流定义
|
||
/// </summary>
|
||
public async Task RunAsync(WorkflowDefinition definition, WorkflowContext context)
|
||
{
|
||
await RunWithResultAsync(definition, context, null);
|
||
}
|
||
|
||
public Task<WorkflowRunCompletedEventArgs> RunWithResultAsync(WorkflowDefinition definition, WorkflowContext context)
|
||
{
|
||
return RunWithResultAsync(definition, context, null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 运行完整的工作流定义,并支持从指定步骤启动。
|
||
/// </summary>
|
||
/// <param name="definition">工作流定义</param>
|
||
/// <param name="context">工作流上下文</param>
|
||
/// <param name="startStepId">可选:指定起始步骤ID;为 null/空时从初始步骤启动</param>
|
||
public async Task RunAsync(WorkflowDefinition definition, WorkflowContext context, string startStepId)
|
||
{
|
||
await RunWithResultAsync(definition, context, startStepId);
|
||
}
|
||
|
||
public async Task<WorkflowRunCompletedEventArgs> RunWithResultAsync(WorkflowDefinition definition, WorkflowContext context, string startStepId)
|
||
{
|
||
if (definition == null) throw new ArgumentNullException(nameof(definition));
|
||
if (context == null) throw new ArgumentNullException(nameof(context));
|
||
|
||
if (IsRunning)
|
||
{
|
||
throw new InvalidOperationException("当前已有流程正在运行,无法重复启动。");
|
||
}
|
||
|
||
if (!string.IsNullOrWhiteSpace(startStepId) && !definition.GetAllStepIds().Contains(startStepId))
|
||
{
|
||
throw new ArgumentException($"指定的起始步骤ID '{startStepId}' 不存在于工作流定义中。", nameof(startStepId));
|
||
}
|
||
|
||
var resolvedStartStepId = ResolveStartStepId(definition, context, startStepId);
|
||
|
||
var errorStr = string.Empty;
|
||
WorkflowState finalState = WorkflowState.Created;
|
||
MessageKey failureMessageKey = MessageKey.None;
|
||
object[] failureMessageArguments = Array.Empty<object>();
|
||
string failureMessage = string.Empty;
|
||
|
||
try
|
||
{
|
||
IsRunning = true;
|
||
_workflowEngine = new WorkflowEngine(definition, context);
|
||
_workflowEngine.Start(resolvedStartStepId);
|
||
|
||
// 异步轮询等待工作流结束
|
||
// 这样可以不阻塞 UI 线程,同时保持 IsRunning 状态正确
|
||
while (_workflowEngine != null && _workflowEngine.IsWorkflowRunning)
|
||
{
|
||
await Task.Delay(100);
|
||
}
|
||
|
||
// 捕获最终状态(Dispose 之前)
|
||
if (_workflowEngine != null)
|
||
{
|
||
finalState = _workflowEngine.CurrentState;
|
||
}
|
||
|
||
failureMessageKey = ResolveFailureMessageKey(context);
|
||
failureMessageArguments = ResolveFailureMessageArguments(context);
|
||
failureMessage = ResolveFailureMessage(context, failureMessageKey, failureMessageArguments);
|
||
}
|
||
finally
|
||
{
|
||
// 无论正常结束、异常还是被取消,都确保清理资源和复位状态
|
||
errorStr = _workflowEngine?.LastException?.ToString();
|
||
IsRunning = false;
|
||
_workflowEngine?.Dispose();
|
||
_workflowEngine = null;
|
||
}
|
||
|
||
var completedArgs = new WorkflowRunCompletedEventArgs(finalState, errorStr, failureMessage, failureMessageKey, failureMessageArguments);
|
||
RunCompleted?.Invoke(this, completedArgs);
|
||
|
||
return completedArgs;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从指定步骤启动工作流(语义化封装)。
|
||
/// </summary>
|
||
public Task RunFromStepAsync(WorkflowDefinition definition, WorkflowContext context, string startStepId)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(startStepId))
|
||
throw new ArgumentNullException(nameof(startStepId));
|
||
|
||
return RunAsync(definition, context, startStepId);
|
||
}
|
||
|
||
public Task<WorkflowRunCompletedEventArgs> RunFromStepWithResultAsync(WorkflowDefinition definition, WorkflowContext context, string startStepId)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(startStepId))
|
||
throw new ArgumentNullException(nameof(startStepId));
|
||
|
||
return RunWithResultAsync(definition, context, startStepId);
|
||
}
|
||
|
||
private string ResolveStartStepId(WorkflowDefinition definition, WorkflowContext context, string startStepId)
|
||
{
|
||
if (!string.IsNullOrWhiteSpace(startStepId))
|
||
{
|
||
return startStepId;
|
||
}
|
||
|
||
if (!context.TryGetData<string>(WorkflowContextKeys.WorkflowName, out var workflowName) ||
|
||
string.IsNullOrWhiteSpace(workflowName) ||
|
||
!context.TryGetData<ProcessResultManager>(WorkflowContextKeys.ProcessResultManager, out var resultManager) ||
|
||
resultManager == null ||
|
||
!resultManager.TryGetResumeStepId(workflowName, out var resumeStepId) ||
|
||
!definition.ContainsStep(resumeStepId))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
return resumeStepId;
|
||
}
|
||
|
||
private MessageKey ResolveFailureMessageKey(WorkflowContext context)
|
||
{
|
||
MessageKey failureMessageKey;
|
||
if (context.TryGetData<MessageKey>(WorkflowContextKeys.WorkflowFailureMessageKey, out failureMessageKey))
|
||
{
|
||
return failureMessageKey;
|
||
}
|
||
|
||
return MessageKey.None;
|
||
}
|
||
|
||
private object[] ResolveFailureMessageArguments(WorkflowContext context)
|
||
{
|
||
object[] failureMessageArguments;
|
||
if (context.TryGetData<object[]>(WorkflowContextKeys.WorkflowFailureMessageArguments, out failureMessageArguments) &&
|
||
failureMessageArguments != null)
|
||
{
|
||
return failureMessageArguments;
|
||
}
|
||
|
||
return Array.Empty<object>();
|
||
}
|
||
|
||
private string ResolveFailureMessage(WorkflowContext context, MessageKey failureMessageKey, object[] failureMessageArguments)
|
||
{
|
||
if (failureMessageKey != MessageKey.None)
|
||
{
|
||
return LanguageResourceHelper.Format(failureMessageKey, failureMessageArguments);
|
||
}
|
||
|
||
string failureMessage;
|
||
if (context.TryGetData<string>(WorkflowContextKeys.WorkflowFailureMessage, out failureMessage) &&
|
||
!string.IsNullOrWhiteSpace(failureMessage))
|
||
{
|
||
return failureMessage;
|
||
}
|
||
|
||
return string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 请求停止当前流程
|
||
/// </summary>
|
||
public async Task StopAsync()
|
||
{
|
||
if (_workflowEngine != null && _workflowEngine.IsWorkflowRunning)
|
||
{
|
||
await _workflowEngine.StopAsync();
|
||
}
|
||
}
|
||
|
||
public void Pause()
|
||
{
|
||
if (_workflowEngine != null && _workflowEngine.IsWorkflowRunning)
|
||
{
|
||
_workflowEngine.Pause();
|
||
}
|
||
}
|
||
|
||
public void Resume()
|
||
{
|
||
if (_workflowEngine != null && _workflowEngine.IsWorkflowRunning)
|
||
{
|
||
_workflowEngine.Resume();
|
||
}
|
||
}
|
||
|
||
public void Dispose()
|
||
{
|
||
_workflowEngine?.Dispose();
|
||
}
|
||
}
|
||
}
|