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 또는 public 메서드 내에서 호출해야합니다. OnEntry에서 전환하는 동안 문제가 발생하면 어떻게됩니까? 무국적자를 사용하여 코드를 구현 한 사람들과 실제 코드를 작성한 사람들의 지침은 크게 감사하겠습니다. – dandcg

답변

11

구조 자체가 몇 가지 발언 해결하기 전에 :

  • OnEntry 행동은 트리거가 성공적으로 발사 된 경우 실행됩니다.

  • 현재 상태에서 허용되지 않는 트리거는 InvalidOperationException을 던집니다. 예외를 예상하지 않으면 OnUnhandledTrigger을 무시하는 것이 좋습니다. 처리되지 않은 트리거를 로깅하는 것이 논리의 결함을 찾는 좋은 방법입니다. OnEntry/OnExit 구조에 대한 엄지 손가락의

내 규칙은 생성과 논리가 OnEntry을 배치하고 필요한 청소가 OnExit을 수행한다는 것이다.

당신의 경우, 당신이 주입 된 의존성을 사용하고 있다는 것을 전제로합니다 (누군가의 소유권을 얻지 못한다고 가정 할 때, 즉 누군가 다른 사람의 라이프 사이클을 관리 할 것입니다). 귀하의 모든 로직을 배치 할 수 있습니다. OnEntry.

상태 머신이 현재 구조화되어있는 방식은 완벽합니다.

하나의 마지막 참고 사항, 상태 기계를 전진시키고 상태 머신 논리를 수행하는 동일한 스레드 내에서 트리거를 시작하면 스택 오버 플로우 예외가 발생할 수 있으며 이로 인해 자동 진행 문제를 해결하는 방법에 대해서는 here을 참조하십시오.

+0

안녕하세요 옴니, 감사합니다. OnEntry 구현 중에 오류가 발생하면 어떻게됩니까? 상태는 여전히 변경됩니까? 또한 일반적으로 워크 플로 인스턴스를 만들기 위해 팩토리를 사용 하시겠습니까?이것은 wf 인스턴스를 시작 상태로 새롭게 처리하고 구현에 필요한 종속성을 전달하는 것을 다룰 것입니다. – dandcg

+0

안녕하세요 @ dandcg. 상태 전이는'OnEntry'가 처리되기 전에 발생하기 때문에 예외가 던질 때까지 상태는 이미 변경됩니다. 그런 다음 예외를 처리 할 위치를 결정해야합니다. 예외를 던진 상태로 변환 된'OnEntry' 또는'machine.Fire (...) '내부. 내가 말하는 'AccountWf'를 만들기 위해 공장을 많이 사용하지 않습니다. 팩토리에 따라 매개 변수가 다르면 다른 유형의 기계/구성이 필요합니다. – Omni

+0

워크 플로 인스턴스 자체를 주입하고 싶지 않은 공장의 이유는 무엇입니까? 그러나 나는 이것이 괜찮다고 생각한다. 어떻게 했니? – dandcg