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

generic payload for raising an event throws exception #94

Open
kuldeepGDI opened this issue Jun 12, 2024 · 0 comments
Open

generic payload for raising an event throws exception #94

kuldeepGDI opened this issue Jun 12, 2024 · 0 comments

Comments

@kuldeepGDI
Copy link

kuldeepGDI commented Jun 12, 2024

Hi, I know that this repo is not maintained anymore but nevertheless I have a use case where I use Automatonymous without MT.

I have a sample code here that works but if I use a payload that is coming using generics, i get an exception

Automatonymous.AutomatonymousException: This activity requires a body with the event, but no body was specified.

The working code is from a unit test in the repo.

using Automatonymous;

namespace TestAutomato;

class Instance
{
    public State CurrentState { get; set; }
    public DateTime? Initialized { get; set; }
}


class InstanceStateMachine :
    AutomatonymousStateMachine<Instance>
{
    public InstanceStateMachine()
    {
        During(Initial,
            When(Initialize)
                .TransitionTo(Draft));
        
        During(Draft,
            When(Thing, context => context.Data.PreviousState.Equals(nameof(Draft)))
                .TransitionTo(True)
                .Then(context => context.Raise(SecInitialize)),
            When(Thing, context => !context.Data.PreviousState.Equals(nameof(Draft)))
                .TransitionTo(False));

        DuringAny(
            When(SecInitialize)
                .Then(context => context.Instance.Initialized = DateTime.Now));
    }

    public State Draft { get; private set; }
    public State True { get; private set; }
    public State False { get; private set; }

    public Event<SomeEventFailedContextData> Thing { get; private set; }
    public Event Initialize { get; private set; }
    
    public Event SecInitialize { get; private set; }
}


public record SomeEventFailedContextData(string PreviousState);

then i use this as following

using Automatonymous;
using TestAutomato;

var instance = new Instance();
var machine = new InstanceStateMachine();

await machine.RaiseEvent(instance, machine.Initialize);

await machine.RaiseEvent(instance, machine.Thing, new SomeEventFailedContextData(nameof(InstanceStateMachine.Draft)), CancellationToken.None);

Console.WriteLine(instance.CurrentState);
if (instance.Initialized != null)
{
    Console.WriteLine(instance.Initialized.Value);
}

And this works as expected. however, i want to use the ability to pass payload as generics because i might have many events with their own payload types, so I wanted to use it as following

namespace TestAutomato;

class Instance
{
    public State CurrentState { get; set; }
    public DateTime? Initialized { get; set; }
}


class InstanceStateMachine :
    AutomatonymousStateMachine<Instance>
{
    public InstanceStateMachine()
    {
        During(Initial,
            When(Initialize)
                .TransitionTo(Draft));
        
        During(Draft,
            When(Thing, context => context.Data.PreviousState.Equals(nameof(Draft)))
                .TransitionTo(True)
                .Then(context => context.Raise(SecInitialize)),
            When(Thing, context => !context.Data.PreviousState.Equals(nameof(Draft)))
                .TransitionTo(False));

        DuringAny(
            When(SecInitialize)
                .Then(context => context.Instance.Initialized = DateTime.Now));
    }

    public State Draft { get; private set; }
    public State True { get; private set; }
    public State False { get; private set; }

    public Event<SomeEventFailedContextData> Thing { get; private set; }
    public Event Initialize { get; private set; }
    
    public Event SecInitialize { get; private set; }
}


public record SomeEventFailedContextData(string PreviousState);

public record GenericSpec<T>(T Payload) where T: class;

and then call it as in

await SomeMethod(new GenericSpec<SomeEventFailedContextData>(new SomeEventFailedContextData(nameof(InstanceStateMachine.Draft))));


async Task SomeMethod<T>(GenericSpec<T> data) where T: class
{
    var instance = new Instance();
    var machine = new InstanceStateMachine();

    await machine.RaiseEvent(instance, machine.Initialize);

    await machine.RaiseEvent(instance, machine.Thing, data.Payload, CancellationToken.None);

    Console.WriteLine(instance.CurrentState);
    if (instance.Initialized != null)
    {
        Console.WriteLine(instance.Initialized.Value);
    }
}

which results into the above mentioned error ! Is there no way to do this or achieve this somehow or am I missing some configuration ?

Additionally, I also notice that if i do following

using Automatonymous;
using TestAutomato;

var instance = new Instance();
var machine = new InstanceStateMachine();

await machine.RaiseEvent(instance, machine.Initialize);
var nextEvents = await machine.NextEvents(instance);

var allowedEvent = nextEvents.FirstOrDefault(x => x.Name.Equals(nameof(machine.Thing)));

await machine.RaiseEvent(instance, allowedEvent, new SomeEventFailedContextData(nameof(InstanceStateMachine.Draft)), CancellationToken.None);

Console.WriteLine(instance.CurrentState);
if (instance.Initialized != null)
{
    Console.WriteLine(instance.Initialized.Value);
}

Then as well RaiseEvent throws the same error. So when

  1. I use generic payload i receive this error
  2. If I use Event which is coming from nextEvents FirstOrDefault then I receive same error. However, call to RaiseEvent works fine If the other override of RaiseEvent as following is used.

await machine.RaiseEvent(instance, allowedEvent, CancellationToken.None); //assuming there is no context arguments required for this event in state machine

Thanks

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

1 participant