Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check available transitions #450

Open
anatoly-kryzhanovsky opened this issue May 12, 2021 · 8 comments
Open

Check available transitions #450

anatoly-kryzhanovsky opened this issue May 12, 2021 · 8 comments

Comments

@anatoly-kryzhanovsky
Copy link

anatoly-kryzhanovsky commented May 12, 2021

I need to have method which return true if transition with specified trigger and parameters available for current state.
because there are parameters i can't use CanFire, so i write following code:

public bool CanApply(TTriggers trigger, params object[] arguments)
{
	if(arguments == null || arguments.Length == 0)
		return StateMachine.CanFire(trigger);
	
	var permittedTriggers = StateMachine.GetPermittedTriggers(arguments);
	return permittedTriggers.Any(x => Equals(x, trigger));
}

and it works perfectly, but not always.

for example i have state machine with following transitions:

  • new -> review, with string parameter (like reason)
  • new -> onprogress with guid parameter (like document id)

now, then i call CanApply method with SendToWork as trigger and Guid as argument the ArgumentException was throwed. Stateless try to convert Guid to string.

i can't find any workaround to get available transition.
The PermittedTriggers property also throw exception (but another - NullReference)

Environment:

  • Platform: .net core 3.1
  • Stateless: 5.11.0
@anatoly-kryzhanovsky
Copy link
Author

i create MVP for reproduce that case

enum Triggers
{
      SendToReview,
      SendToWork
  }

  enum States
  {
      New,
      Review,
      InProgress
  }

  class Entity
  {
      public States State { get; set; }
  }

  class Workflow
  {
      private readonly StateMachine<States,Triggers> _stateMachine;
      
      public bool CanApply(Triggers trigger, params object[] arguments)
      {
          if(arguments == null || arguments.Length == 0)
              return _stateMachine.CanFire(trigger);
	
          var permittedTriggers = _stateMachine.GetPermittedTriggers(arguments);
          return permittedTriggers.Any(x => Equals(x, trigger));
      }

      public Workflow(Entity entity)
      {
          _stateMachine = new StateMachine<States, Triggers>(() => entity.State, state => entity.State = state);
          var sendToReviewTrigger = _stateMachine.SetTriggerParameters<string>(Triggers.SendToReview);
          
          _stateMachine.Configure(States.New)
              .PermitIf(
                  sendToReviewTrigger,
                  States.Review,
                  _ => true);
      }
  }
  
  class Program
  {
      static void Main(string[] args)
      {
          var entity = new Entity
          {
              State = States.New
          };
          var workflow = new Workflow(entity);
          var canApply = workflow.CanApply(Triggers.SendToWork, Guid.NewGuid());
      }
  }

so the problem is guard for action. stateless try to invoke guard _ => true, but _ in this case is string, check method invoked with Guid and exception will be throwed

any idea to fix this?

@anatoly-kryzhanovsky
Copy link
Author

i created pull request #451 for that case

@DeepakParamkusam
Copy link
Contributor

I do not understand your MVP. You have a string as a trigger parameter but want to use a Guid instead? Stateless throwing an ArgumentException is correct behavior in this case. Either convert your Guid to a string or use another trigger with Guid as a parameter.

I need to have method which return true if transition with specified trigger and parameters available for current state.
because there are parameters i can't use CanFire

Since this your main requirement, it should be trivial to add an overload to CanFire that accepts parameters. I added a similar overload in #443. However, Stateless would still throw if you try to pass a Guid when it expects a string.

@anatoly-kryzhanovsky
Copy link
Author

anatoly-kryzhanovsky commented May 17, 2021

i post only code for reproduce. in real case i have more transition:
for example i have transition new -> Review with string argument and new -> inwork with guid argument

so, than i try to check is transition available ithe argumentexception was throwed

UPD:
i want have CanFire in my base interface, because i use it in generic web request approvers, so i can't write CanFire for each available transition

@anatoly-kryzhanovsky
Copy link
Author

additional notice - method with name GetPermittedTriggers shouldn't throw exception if argument type does not much guard type. If there is no guard for that type then trigger is not permitted. by convention.
this is only my opinion

@WahidBitar
Copy link

WahidBitar commented Aug 15, 2021

I've created a pull request to resolve the exception when GetPermittedTriggers #457

@WahidBitar
Copy link

@HenningNT May you please pick one of the pull requests to fix this issue?
I guess there is no need to throw an exception when trying to get the Permitted Triggers.

@WahidBitar
Copy link

up

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants