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

Make transition actions async-first #452

Open
wants to merge 27 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
26d84fb
Introduce EventCallback
sunghwan2789 May 22, 2021
3708be8
Use EventCallback in ActivateAction
sunghwan2789 May 22, 2021
b6c78c2
Use EventCallback in DeactivateAction
sunghwan2789 May 22, 2021
641cf30
Use EventCallback in ExitAction
sunghwan2789 May 22, 2021
ca8d073
Use EventCallback in EntryAction
sunghwan2789 May 22, 2021
aeefd3d
Use EventCallback in InternalAction
sunghwan2789 May 22, 2021
7ad8b37
Use EventCallback in TransitionedAction
sunghwan2789 May 22, 2021
7d81abe
Use EventCallback in UnhandledTriggerAction
sunghwan2789 May 22, 2021
b33bdc5
Use TaskResult.Done for old .net sdk
sunghwan2789 May 22, 2021
75c429c
Delete internal synchronous code
sunghwan2789 May 22, 2021
89e1b03
Delete internal synchronous methods
sunghwan2789 May 22, 2021
9f3bfaf
Delete synchronous EnterState
sunghwan2789 May 22, 2021
4e72686
Delete synchronous HandleReentryTrigger
sunghwan2789 May 22, 2021
d3b460b
Delete synchronous HandleTransitioningTrigger
sunghwan2789 May 22, 2021
61d3c10
Delete synchronous HandleInternalTrigger
sunghwan2789 May 22, 2021
6b98c75
Delete synchronous InternalFireOne
sunghwan2789 May 22, 2021
61db67f
Delete synchronous InternalFireQueued
sunghwan2789 May 22, 2021
21ec879
Delete synchronous InternalFire
sunghwan2789 May 22, 2021
bff894d
Make synchronous Fire proxy async method
sunghwan2789 May 22, 2021
9b4f572
Add postfix to async methods
sunghwan2789 May 22, 2021
5d53d5f
Delete TASKS compilation guards
sunghwan2789 May 22, 2021
5f42cb9
Add Microsoft.Bcl.Async on .NET FW 4.0 build
sunghwan2789 May 22, 2021
0dcaf3c
Add missing ConfigureAwait(false)
sunghwan2789 May 22, 2021
ba36bf1
Move EventCallbackFactory call to ctor
sunghwan2789 May 23, 2021
815b8ef
Add test cases for OnTransitionedEvent
sunghwan2789 May 23, 2021
82690a7
Add test case for async code in a sync action
sunghwan2789 May 23, 2021
e4219d7
Add missing api of StateConfiguration
sunghwan2789 May 23, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 16 additions & 46 deletions src/Stateless/ActivateActionBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,64 +5,34 @@ namespace Stateless
{
public partial class StateMachine<TState, TTrigger>
{
internal abstract class ActivateActionBehaviour
internal class ActivateActionBehaviour
{
readonly TState _state;
private readonly EventCallback _callback;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use EventCallback is not enought good solution. library can used in simple console host application that does not have this dependency


protected ActivateActionBehaviour(TState state, Reflection.InvocationInfo actionDescription)
public ActivateActionBehaviour(TState state, Action action, Reflection.InvocationInfo actionDescription)
: this(state, actionDescription)
{
_state = state;
Description = actionDescription ?? throw new ArgumentNullException(nameof(actionDescription));
_callback = EventCallbackFactory.Create(action);
}

internal Reflection.InvocationInfo Description { get; }

public abstract void Execute();
public abstract Task ExecuteAsync();

public class Sync : ActivateActionBehaviour
public ActivateActionBehaviour(TState state, Func<Task> action, Reflection.InvocationInfo actionDescription)
: this(state, actionDescription)
{
readonly Action _action;

public Sync(TState state, Action action, Reflection.InvocationInfo actionDescription)
: base(state, actionDescription)
{
_action = action;
}

public override void Execute()
{
_action();
}

public override Task ExecuteAsync()
{
Execute();
return TaskResult.Done;
}
_callback = EventCallbackFactory.Create(action);
}

public class Async : ActivateActionBehaviour
protected ActivateActionBehaviour(TState state, Reflection.InvocationInfo actionDescription)
{
readonly Func<Task> _action;

public Async(TState state, Func<Task> action, Reflection.InvocationInfo actionDescription)
: base(state, actionDescription)
{
_action = action;
}
_state = state;
Description = actionDescription ?? throw new ArgumentNullException(nameof(actionDescription));
}

public override void Execute()
{
throw new InvalidOperationException(
$"Cannot execute asynchronous action specified in OnActivateAsync for '{_state}' state. " +
"Use asynchronous version of Activate [ActivateAsync]");
}
internal Reflection.InvocationInfo Description { get; }

public override Task ExecuteAsync()
{
return _action();
}
public virtual Task ExecuteAsync()
{
return _callback.InvokeAsync();
}
}
}
Expand Down
62 changes: 16 additions & 46 deletions src/Stateless/DeactivateActionBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,64 +5,34 @@ namespace Stateless
{
public partial class StateMachine<TState, TTrigger>
{
internal abstract class DeactivateActionBehaviour
internal class DeactivateActionBehaviour
{
readonly TState _state;
private readonly EventCallback _callback;

protected DeactivateActionBehaviour(TState state, Reflection.InvocationInfo actionDescription)
public DeactivateActionBehaviour(TState state, Action action, Reflection.InvocationInfo actionDescription)
: this(state, actionDescription)
{
_state = state;
Description = actionDescription ?? throw new ArgumentNullException(nameof(actionDescription));
_callback = EventCallbackFactory.Create(action);
}

internal Reflection.InvocationInfo Description { get; }

public abstract void Execute();
public abstract Task ExecuteAsync();

public class Sync : DeactivateActionBehaviour
public DeactivateActionBehaviour(TState state, Func<Task> action, Reflection.InvocationInfo actionDescription)
: this(state, actionDescription)
{
readonly Action _action;

public Sync(TState state, Action action, Reflection.InvocationInfo actionDescription)
: base(state, actionDescription)
{
_action = action;
}

public override void Execute()
{
_action();
}

public override Task ExecuteAsync()
{
Execute();
return TaskResult.Done;
}
_callback = EventCallbackFactory.Create(action);
}

public class Async : DeactivateActionBehaviour
protected DeactivateActionBehaviour(TState state, Reflection.InvocationInfo actionDescription)
{
readonly Func<Task> _action;

public Async(TState state, Func<Task> action, Reflection.InvocationInfo actionDescription)
: base(state, actionDescription)
{
_action = action;
}
_state = state;
Description = actionDescription ?? throw new ArgumentNullException(nameof(actionDescription));
}

public override void Execute()
{
throw new InvalidOperationException(
$"Cannot execute asynchronous action specified in OnDeactivateAsync for '{_state}' state. " +
"Use asynchronous version of Deactivate [DeactivateAsync]");
}
internal Reflection.InvocationInfo Description { get; }

public override Task ExecuteAsync()
{
return _action();
}
public virtual Task ExecuteAsync()
{
return _callback.InvokeAsync();
}
}
}
Expand Down
75 changes: 25 additions & 50 deletions src/Stateless/EntryActionBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,81 +5,56 @@ namespace Stateless
{
public partial class StateMachine<TState, TTrigger>
{
internal abstract class EntryActionBehavior
internal class EntryActionBehavior
{
private readonly EventCallback<Transition, object[]> _callback;

public EntryActionBehavior(Action<Transition, object[]> action, Reflection.InvocationInfo description)
: this(description)
{
_callback = EventCallbackFactory.Create(action);
}

public EntryActionBehavior(Func<Transition, object[], Task> action, Reflection.InvocationInfo description)
: this(description)
{
_callback = EventCallbackFactory.Create(action);
}

protected EntryActionBehavior(Reflection.InvocationInfo description)
{
Description = description;
}

public Reflection.InvocationInfo Description { get; }

public abstract void Execute(Transition transition, object[] args);
public abstract Task ExecuteAsync(Transition transition, object[] args);

public class Sync : EntryActionBehavior
public virtual Task ExecuteAsync(Transition transition, object[] args)
{
readonly Action<Transition, object[]> _action;

public Sync(Action<Transition, object[]> action, Reflection.InvocationInfo description) : base(description)
{
_action = action;
}

public override void Execute(Transition transition, object[] args)
{
_action(transition, args);
}

public override Task ExecuteAsync(Transition transition, object[] args)
{
Execute(transition, args);
return TaskResult.Done;
}
return _callback.InvokeAsync(transition, args);
}

public class SyncFrom<TTriggerType> : Sync
public class From<TTriggerType> : EntryActionBehavior
{
internal TTriggerType Trigger { get; private set; }

public SyncFrom(TTriggerType trigger, Action<Transition, object[]> action, Reflection.InvocationInfo description)
public From(TTriggerType trigger, Action<Transition, object[]> action, Reflection.InvocationInfo description)
: base(action, description)
{
Trigger = trigger;
}

public override void Execute(Transition transition, object[] args)
public From(TTriggerType trigger, Func<Transition, object[], Task> action, Reflection.InvocationInfo description)
: base(action, description)
{
if (transition.Trigger.Equals(Trigger))
base.Execute(transition, args);
Trigger = trigger;
}

public override Task ExecuteAsync(Transition transition, object[] args)
{
Execute(transition, args);
return TaskResult.Done;
}
}

public class Async : EntryActionBehavior
{
readonly Func<Transition, object[], Task> _action;

public Async(Func<Transition, object[], Task> action, Reflection.InvocationInfo description) : base(description)
{
_action = action;
}

public override void Execute(Transition transition, object[] args)
{
throw new InvalidOperationException(
$"Cannot execute asynchronous action specified in OnEntry event for '{transition.Destination}' state. " +
"Use asynchronous version of Fire [FireAsync]");
}
if (transition.Trigger.Equals(Trigger))
return base.ExecuteAsync(transition, args);

public override Task ExecuteAsync(Transition transition, object[] args)
{
return _action(transition, args);
return TaskResult.Done;
}
}
}
Expand Down
Loading