我有一个项目,其中主要是线性工作流程。我正在尝试使用.NET Stateless library作为工作流引擎/状态机。那里的例子数量有限,但我把以下代码放在一起:
private StateMachine<WorkflowStateType, WorkflowStateTrigger> stateMachine;
private StateMachine<WorkflowStateType, WorkflowStateTrigger>.TriggerWithParameters<Guid, DateTime> registrationTrigger;
private Patient patient;
public Patient RegisterPatient(DateTime dateOfBirth)
{
configureStateMachine(WorkflowState.Unregistered);
stateMachine.Fire<DateTime>(registrationTrigger, dateOfBirth);
logger.Info("State changed to: " + stateMachine.State);
return patient;
}
private void configureStateMachine(WorkflowState state)
{
stateMachine = new StateMachine<WorkflowState, WorkflowTrigger>(state);
registrationTrigger = stateMachine.SetTriggerParameters<DateTime>(WorkflowTrigger.Register);
stateMachine.Configure(WorkflowState.Unregistered)
.Permit(WorkflowTrigger.Register, WorkflowStateType.Registered);
stateMachine.Configure(WorkflowState.Registered)
.Permit(WorkflowTrigger.ScheduleSampling, WorkflowState.SamplingScheduled)
.OnEntryFrom(registrationTrigger, (dateOfBirth) => registerPatient(dateOfBirth));
}
private void registerPatient(DateTime dateOfBirth)
{
//Registration code
}
正如您所看到的,我正在使用Stateless Fire()重载,它允许我传入一个触发器。这样我就可以拥有状态机进程业务逻辑,在这种情况下,代码可以注册一个新患者。
这一切都有效,但是现在我想将所有状态机代码移动到另一个类中来封装它,我在执行此操作时遇到了麻烦。我这样做的挑战是:
StateMachine
对象需要您指定状态,State
是一个只能在实例化时设置的只读属性。registrationTrigger
必须在状态机配置期间实例化,并且必须由调用类提供。如何克服这些项并封装状态机代码?
答案 0 :(得分:7)
Scott Hanselman有一个article的例子和图书馆介绍。另外,他们的GitHub上提供的示例很少,包括在Scott的文章中提到的Bug implementation example封装了状态机。
以下是如何从行为中提取状态的示例:
public class PatientRegistrationState
{
private StateMachine<WorkflowState, WorkflowTrigger> stateMachine;
private StateMachine<WorkflowState, WorkflowStateTrigger>.TriggerWithParameters<DateTime> registrationTrigger;
public PatientRegistrationState(State initialState = default(State)) {
stateMachine = new StateMachine<WorkflowState, WorkflowTrigger>(initialState);
stateMachine.Configure(WorkflowState.Unregistered)
.Permit(WorkflowTrigger.Register, WorkflowStateType.Registered);
stateMachine.Configure(WorkflowState.Registered)
.Permit(WorkflowTrigger.ScheduleSampling, WorkflowState.SamplingScheduled)
.OnEntryFrom(registrationTrigger, (date) => OnPatientRegistered(date));
}
public WorkflowState State => stateMachine.State;
public Action<DateTime> OnPatientRegistered {get; set;} = (date) => { };
// For state changes that do not require parameters.
public void ChangeTo(WorkflowTrigger trigger)
{
stateMachine.Fire<DateTime>(trigger);
}
// For state changes that require parameters.
public void ChangeToRegistered(DateTime dateOfBirth)
{
stateMachine.Fire<DateTime>(registrationTrigger, dateOfBirth);
}
// Change to other states that require parameters...
}
public class PatientRegistration
{
private PatientRegistrationState registrationState;
private Patient patient;
public PatientRegistration()
{
registrationState = PatientRegistrationState(WorkflowState.Unregistered)
{
OnPatientRegistered = RegisterPatient;
}
}
public Patient RegisterPatient(DateTime dateOfBirth)
{
registrationState.ChangeToRegistered(dateOfBirth);
logger.Info("State changed to: " + registrationState.State);
return patient;
}
private void RegisterPatient(DateTime dateOfBirth)
{
// Registration code
}
}
答案 1 :(得分:3)
这就是我在项目中实现它的方式。
分离的工作流逻辑以分离类。我有几个基于请求对象中存在的标志之一的工作流程;下面是工作流程类之一:
public class NationalWorkflow : BaseWorkflow
{
public NationalWorkflow(SwiftRequest request) : this(request, Objects.RBDb)
{ }
public NationalWorkflow(SwiftRequest request, RBDbContext dbContext)
{
this.request = request;
this.dbContext = dbContext;
this.ConfigureWorkflow();
}
protected override void ConfigureWorkflow()
{
workflow = new StateMachine<SwiftRequestStatus, SwiftRequestTriggers>(
() => request.SwiftRequestStatus, state => request.SwiftRequestStatus = state);
workflow.OnTransitioned(Transitioned);
workflow.Configure(SwiftRequestStatus.New)
.OnEntry(NotifyRequestCreation)
.Permit(SwiftRequestTriggers.ProcessRequest, SwiftRequestStatus.InProgress);
workflow.Configure(SwiftRequestStatus.InProgress)
.OnEntry(ValidateRequestEligibility)
.Permit(SwiftRequestTriggers.AutoApprove, SwiftRequestStatus.Approved)
.Permit(SwiftRequestTriggers.AdvancedServicesReview, SwiftRequestStatus.PendingAdvancedServices);
.....................
}
从控制器/任何其他层触发:
private static void UpdateRequest(SwiftRequestDTO dtoRequest)
{
var workflow = WorkflowFactory.Get(request);
workflow.UpdateRequest();
}
如上所述,我根据请求对象中的条件使用了不同的工作流程规则,因此使用了工厂模式WorkflowFactory.Get(request)
;您可以创建工作流的实例/根据需要注入
在工作流类(我的情况下是BaseWorkflow类)中,我已经公开了这些操作:
public void UpdateRequest()
{
using (var trans = this.dbContext.Database.BeginTransaction())
{
this.actionComments = "Updating the request";
this.TryFire(SwiftRequestTriggers.Update);
SaveChanges();
trans.Commit();
}
}
protected void TryFire(SwiftRequestTriggers trigger)
{
if (!workflow.CanFire(trigger))
{
throw new Exception("Cannot fire " + trigger.ToString() + " from state- " + workflow.State);
}
workflow.Fire(trigger);
}