10

Come le persone strutturano il loro codice quando usano la libreria stateless C#?Libreria macchine con stato stateless - modo appropriato per strutturare?

https://github.com/nblumhardt/stateless

Sono particolarmente interessato a come questo si lega con dipendenze iniettati, e un corretto approccio di responsabilità e stratificazione in modo corretto.

mio attuale struttura prevede:

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); 
    } 

} 

Dovremmo implementare tutti i processi (chiamata ai servizi) all'interno del gancio OnEntry, o implementare i processi all'esterno dopo la transizione di stato è stato verificato che è permesso di avere luogo? Mi chiedo come fare la gestione delle transazioni in caso affermativo.

Immagino che quello che sto cercando sia una guida migliore da parte di coloro che hanno già implementato qualcosa usando gli apolidi e come avvicinarsi alla struttura del codice.

+0

Considerando questo aspetto, mi sto orientando verso l'utilizzo di uno stabilimento immesso nei servizi di dominio per costruire l'oggetto del flusso di lavoro e questo può passare nei servizi richiesti dall'oggetto del flusso di lavoro. – dandcg

+0

Ancora guardando alcune linee guida sull'approccio migliore all'uso della macchina a stati. Suppongo di dover chiamare un metodo su un servizio di posta elettronica di invio che esiste per tutta la durata della richiesta web. Se questa chiamata dovesse andare all'interno di OnEntry o all'interno del metodo pubblico. Se è nella OnEntry cosa succede se c'è un problema durante la transizione? Alcuni consigli da persone che hanno implementato il codice utilizzando gli apolidi e dove hanno inserito il codice di esecuzione effettivo sarebbero molto apprezzati. – dandcg

risposta

11

Prima di affrontare la struttura stessa un paio di osservazioni:

  • OnEntry azioni vengono eseguite solo se il grilletto è stato licenziato con successo.

  • I trigger attivati ​​che non sono consentiti nello stato corrente generano uno InvalidOperationException. Considerare di ignorare OnUnhandledTrigger se non si prevede un'eccezione (ho scoperto che la registrazione di trigger non gestiti è un buon approccio per trovare i difetti nella logica).

La mia regola per la OnEntry/OnExit strutturazione è che ogni creazione e la logica saranno collocati OnEntry e qualsiasi richiesta di clean-up è fatto OnExit.

Quindi nel tuo caso, dato che stai usando le dipendenze iniettate (e supponendo che tu non ne assumi la proprietà, cioè che qualcun altro gestirà il loro ciclo di vita) puoi mettere tutta la tua logica OnEntry.

Con questo in mente, il modo in cui la macchina di stato è attualmente strutturata è perfettamente a posto.

Un'ultima nota, tenere presente che la cottura trigger dall'interno stesso thread che sta avanzando la macchina dello Stato e fare la logica di macchina a stati può e porterà a StackOverflow eccezioni (vedi here su come risolvere il problema avanzamento automatico).

+0

Ciao Omni, grazie per questo. cosa succederebbe allora se si verificasse un errore durante l'implementazione OnEntry - lo stato cambierebbe ancora? Inoltre, utilizzeresti in genere una fabbrica per creare l'istanza del flusso di lavoro?Questo avrebbe a che fare con l'aggiornamento dell'istanza wf con lo stato di partenza e il passaggio delle dipendenze richieste dall'implementazione? – dandcg

+0

Ciao @dandcg. La transizione di stato avviene prima che venga elaborato il comando "OnEntry", quindi nel momento in cui viene generata l'eccezione, lo stato è già stato modificato. Devi quindi decidere dove gestire l'eccezione. O all'interno di "OnEntry" o in "machine.Fire (...)" che è passato allo stato che ha generato l'eccezione. Non c'è molto da usare in una fabbrica per creare il 'AccountWf' direi. Una factory sarebbe utile se, in base ai parametri, avessi diversi tipi di macchine/configurazioni. – Omni

+0

Il motivo per cui la fabbrica è che non voglio iniettare l'istanza del flusso di lavoro stessa? Ma suppongo che questo sia ok. Come hai giocato? – dandcg

Problemi correlati