10

在使用c#無狀態庫時,人們如何構造代碼?無狀態狀態機庫 - 適當的結構方式?

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 2014-10-09 15:44:39

+0

仍在尋找關於使用狀態機的最佳方法的一些指導。假設我需要在發送電子郵件服務時調用一個方法,該方法在Web請求的整個生命週期中都存在。這個呼叫應該在OnEntry中還是在公共方法中進行。如果它在OnEntry中如果在轉換過程中遇到問題會發生什麼?有些人已經使用無狀態實現代碼,並且他們已經放置了實際代碼的一些指導將不勝感激。 – dandcg 2014-10-12 15:55:24

回答

11

解決結構本身一對夫婦的言論之前:

  • OnEntry操作僅執行如果觸發已成功發射。

  • 在當前狀態下不允許觸發的觸發器將拋出一個InvalidOperationException。如果您不期待發生異常(我發現記錄未處理的觸發器是找到邏輯中的缺陷的好方法),請考慮覆蓋OnUnhandledTrigger

我的經驗爲OnEntry/OnExit結構的規則是,任何創造和邏輯將被放置OnEntry和任何所需的清理做OnExit

所以在你的情況下,考慮到你正在使用注入的依賴關係(並假設你沒有取得那些所有權,即別人會管理他們的生命週期),你可以放置所有的邏輯OnEntry

考慮到這一點,你的狀態機目前的結構方式非常好。最後一個注意事項,請記住,在同一個線程內觸發觸發器,它將推進狀態機和執行狀態機邏輯,並可能導致堆棧溢出異常(有關如何解決自動超前問題,請參閱here)。

+0

嗨Omni,謝謝你。如果在OnEntry實現期間發生錯誤,那麼會發生什麼? - 狀態是否會改變?你也一般會用工廠來創建工作流實例嗎?這將處理新的wf實例的起始狀態並傳遞實現所需的依賴關係? – dandcg 2014-10-15 10:12:28

+0

Hi @dandcg。狀態轉換髮生在'OnEntry'處理之前,因此在拋出異常時,狀態已經改變。然後您必須決定在哪裏處理異常。在'OnEntry'或者'machine.Fire(...)'內部轉換成拋出異常的狀態。 使用工廠創建'AccountWf'我沒有太多說的。如果取決於參數,工廠將很有用,您有不同類型的機器/配置。 – Omni 2014-10-15 10:33:06

+0

工廠的原因是我不想注入工作流實例本身?但我想這是好的。你是怎麼玩的? – dandcg 2014-10-15 10:36:27