10

Как люди структурируют свой код при использовании библиотеки C# stateless?Библиотека государственной машины без гражданства - соответствующий способ структурирования?

https://github.com/nblumhardt/stateless

Я особенно заинтересован в том, как это вяжется с инжектированными зависимостями, и правильный подход обязанностей и правильно отводки.

Моя текущая структура включает в себя следующее:

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

} 

Если мы реализуем все процессы (вызов услуг) в пределах OnEntry крючка, или осуществлять процессы на внешней стороне после того, как переходное состояние было подтверждено, что разрешено? Мне интересно, как это сделать при управлении транзакциями.

Я предполагаю, что я за ним - это лучшее руководство от тех, кто уже реализовал что-то, используя апатрид и как подойти к структуре кода.

+0

Глядя на это еще немного, я склоняюсь к использованию фабрики, внедренной в службы домена, для создания объекта рабочего процесса, и это может пройти в сервисах, требуемых объектом рабочего процесса. – dandcg

+0

Все еще глядя на некоторые рекомендации по наилучшему подходу к использованию конечного автомата. Скажем, мне нужно вызвать метод на отправке службы электронной почты, которая существует для жизни веб-запроса. Если этот вызов перейдет в OnEntry или в общедоступный метод. Если в OnEntry это происходит, если во время перехода есть проблема? Некоторые рекомендации от людей, которые внедряют код с использованием апатридов и где они разместили фактический код, будут очень благодарны. – dandcg

ответ

11

Прежде чем рассматривать саму структуру пару замечания:

  • OnEntry действия выполняются только если триггер был успешно уволен.

  • Триггеры, которые не разрешены в текущем состоянии, будут вызывать InvalidOperationException. Рассмотрите переопределение OnUnhandledTrigger, если вы не ожидаете исключения (я обнаружил, что ведение журнала необработанных триггеров - хороший подход к поиску недостатков в логике).

Мое правило для структурирования OnEntry/OnExit является то, что любое создание и логика будет помещен OnEntry и любые требуемые очистки делается OnExit.

Так что в вашем случае, учитывая, что вы используете вложенные зависимости (и предполагая, что вы не владеете ими, то есть кто-то другой будет управлять своим жизненным циклом), вы можете разместить всю свою логику OnEntry.

Учитывая это, способ, которым ваш государственный аппарат в настоящее время структурирован, отлично.

Последнее примечание: имейте в виду, что триггеры срабатывания из одного и того же потока, которые продвигают машину состояний и выполняют логику конечного автомата, могут привести к исключениям stackoverflow (см. here о том, как решить проблему автоматического продвижения).

+0

Привет, Omni, спасибо. что тогда произойдет, если ошибка произошла во время реализации OnEntry - будет ли состояние по-прежнему изменяться? Также вы обычно используете фабрику для создания экземпляра рабочего процесса?Это будет связано с обновлением экземпляра wf с начальным состоянием и передачей зависимостей, необходимых для реализации? – dandcg

+0

Привет @dandcg. Переход состояния происходит до обработки 'OnEntry', поэтому к моменту исключения исключается состояние. Затем вам нужно решить, где обращаться с этим исключением. Либо внутри 'OnEntry', либо в' machine.Fire (...) ', который перешел в состояние, в котором было исключение. Не так много в использовании фабрики для создания 'AccountWf', я бы сказал. Завод был бы полезен, если бы в зависимости от параметров у вас были разные типы машин/конфигураций. – Omni

+0

Причина, по которой фабрика заключается в том, что я не хочу вводить сам экземпляр рабочего процесса? Но я полагаю, что все в порядке. Как вы играли в нее? – dandcg