machine c# design state-machines finite-state-machine stateless-state-machine

machine - stateless c#



Stateless state machine library: ¿forma apropiada de estructurar? (1)

Antes de abordar la estructura, un par de comentarios:

  • OnEntry acciones de entrada solo se ejecutan si el desencadenador se ha disparado correctamente.

  • Los disparadores disparados que no están permitidos en el estado actual arrojarán una InvalidOperationException . Considere anular OnUnhandledTrigger si no espera una excepción (he encontrado que el inicio de sesión no controlado desencadena es un buen enfoque para encontrar los defectos en la lógica).

Mi regla de oro para la estructuración OnEntry / OnExit es que cualquier creación y lógica se colocarán OnEntry y cualquier limpieza requerida se realizará OnExit .

Entonces, en su caso, dado que está utilizando dependencias inyectadas (y suponiendo que no se está apropiando de ellas, es decir, alguien más administrará su ciclo de vida) puede colocar toda su lógica OnEntry .

Con eso en mente, la forma en que su máquina de estado está estructurada actualmente está perfectamente bien.

Una última nota, tenga en cuenta que disparar dispara desde dentro del mismo hilo que avanza la máquina de estado y hacer la lógica de máquina de estado puede y dará lugar a excepciones de stackoverflow (consulte aquí cómo resolver el problema de avance automático).

¿Cómo estructuran las personas su código cuando usan la biblioteca c # stateless?

https://github.com/nblumhardt/stateless

Estoy particularmente interesado en cómo esto se relaciona con las dependencias inyectadas, y un enfoque correcto de responsabilidades y estratificación correctamente.

Mi estructura actual implica lo siguiente:

public class AccountWf { private readonly AspNetUser aspNetUser; private enum State { Unverified, VerificationRequestSent, Verfied, Registered } private enum Trigger { VerificationRequest, VerificationComplete, RegistrationComplete } private readonly StateMachine<State, Trigger> machine; public AccountWf(AspNetUser aspNetUser, AccountWfService userAccountWfService) { this.aspNetUser = aspNetUser; if (aspNetUser.WorkflowState == null) { aspNetUser.WorkflowState = State.Unverified.ToString(); } machine = new StateMachine<State, Trigger>( () => (State)Enum.Parse(typeof(State), aspNetUser.WorkflowState), s => aspNetUser.WorkflowState = s.ToString() ); machine.Configure(State.Unverified) .Permit(Trigger.VerificationRequest, State.VerificationRequestSent); machine.Configure(State.VerificationRequestSent) .OnEntry(() => userAccountWfService.SendVerificationRequest(aspNetUser)) .PermitReentry(Trigger.VerificationRequest) .Permit(Trigger.VerificationComplete, State.Verfied); machine.Configure(State.Verfied) .Permit(Trigger.RegistrationComplete, State.Registered); } public void VerificationRequest() { machine.Fire(Trigger.VerificationRequest); } public void VerificationComplete() { machine.Fire(Trigger.VerificationComplete); } public void RegistrationComplete() { machine.Fire(Trigger.RegistrationComplete); } }

¿Deberíamos implementar todos los procesos (llamadas a servicios) dentro del enlace OnEntry, o implementar los procesos en el exterior después de que se haya verificado que la transición de estado está permitida? Me pregunto cómo hacer la gestión de transacciones si es así.

Creo que lo que busco es una mejor guía de aquellos que ya han implementado algo usando apátridas y cómo abordar la estructura del código.