DSeries.DStateMachine.Core 1.0.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package DSeries.DStateMachine.Core --version 1.0.1
                    
NuGet\Install-Package DSeries.DStateMachine.Core -Version 1.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DSeries.DStateMachine.Core" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DSeries.DStateMachine.Core" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="DSeries.DStateMachine.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DSeries.DStateMachine.Core --version 1.0.1
                    
#r "nuget: DSeries.DStateMachine.Core, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=DSeries.DStateMachine.Core&version=1.0.1
                    
Install DSeries.DStateMachine.Core as a Cake Addin
#tool nuget:?package=DSeries.DStateMachine.Core&version=1.0.1
                    
Install DSeries.DStateMachine.Core as a Cake Tool

DStateMachine

DStateMachine is a powerful and flexible asynchronous state machine library for .NET, designed with a clean, fluent API and production-ready architecture. It supports dynamic transitions, guard conditions, entry/exit hooks, and internal transitions, making it ideal for complex stateful workflows.


✨ Features

  • Generic Support: Works with any type for states and triggers (e.g., string, int, enum).
  • Fluent API: Concise and expressive DSL for configuration.
  • Asynchronous Execution: Seamless async/await support for transitions and actions.
  • Entry and Exit Hooks: Configure entry/exit actions per state.
  • Guard Clauses: Conditionally block transitions.
  • Internal Transitions: Perform side-effect actions without state change.
  • Dynamic Transitions: Determine the destination state at runtime.
  • DOT Export: Generate DOT-format graphs for visualization.

📚 Example Usage

var sm = new DStateMachine<string, string>("A");

sm.Configure("A")
    .OnEntry(() => Console.WriteLine("Entering A"))
    .OnExit(() => Console.WriteLine("Exiting A"))
    .OnTrigger("toB", tb => tb.ChangeState("B"));

sm.Configure("B").OnEntry(() => Console.WriteLine("Entered B"));

await sm.FireAsync("toB");
Console.WriteLine(sm.CurrentState); // Output: B

✅ Feature Examples

✅ Generic Type Support

var sm = new DStateMachine<int, int>(0);
sm.Configure(0).OnTrigger(1, tb => tb.ChangeState(2));
sm.Fire(1);
Console.WriteLine(sm.CurrentState); // Output: 2

🔁 Entry and Exit Actions

var sm = new DStateMachine<string, string>("Init");
bool entered = false, exited = false;

sm.Configure("Init")
    .OnEntry(() => { entered = true; return Task.CompletedTask; })
    .OnExit(() => { exited = true; return Task.CompletedTask; })
    .OnTrigger("go", tb => tb.ChangeState("Done"));

sm.Configure("Done").OnEntry(() => Task.CompletedTask);
sm.Fire("go");
Console.WriteLine($"Entered: {entered}, Exited: {exited}"); // Output: Entered: False, Exited: True

⛔ Guard Clauses

var sm = new DStateMachine<string, string>("A");
sm.Configure("A")
    .OnTrigger("toB", tb => tb.ChangeState("B").If(() => false));

sm.OnUnhandledTrigger((trigger, machine) => {
    Console.WriteLine("Blocked by guard");
    return Task.CompletedTask;
});

sm.Fire("toB"); // Output: Blocked by guard

⏳ Asynchronous Transitions

var sm = new DStateMachine<string, string>("Start");
sm.Configure("Start")
    .OnTrigger("load", tb => tb.ChangeStateAsync(async () => {
        await Task.Delay(100);
        return "Loaded";
    }));

sm.Configure("Loaded").OnEntry(() => Task.CompletedTask);
await sm.FireAsync("load");
Console.WriteLine(sm.CurrentState); // Output: Loaded

🧠 Dynamic Transitions

var sm = new DStateMachine<string, string>("A");
sm.Configure("A")
    .OnTrigger("toNext", tb => tb.ChangeState(() => DateTime.Now.Second % 2 == 0 ? "Even" : "Odd"));

sm.Configure("Even").OnEntry(() => Task.CompletedTask);
sm.Configure("Odd").OnEntry(() => Task.CompletedTask);

sm.Fire("toNext");
Console.WriteLine(sm.CurrentState); // Output: "Even" or "Odd"

🔁 Internal Transitions

var sm = new DStateMachine<string, string>("Idle");
bool logged = false;

sm.Configure("Idle")
    .OnTrigger("ping", tb => tb.ExecuteAction(() => logged = true));

await sm.FireAsync("ping");
Console.WriteLine($"State: {sm.CurrentState}, Logged: {logged}");
// Output: State: Idle, Logged: True

💬 Fluent DSL

var sm = new DStateMachine<string, string>("X");
sm.Configure("X")
    .OnTrigger("a", tb => tb.ChangeState("A"))
    .OnTrigger("b", tb => tb.ChangeState("B"));

Console.WriteLine(sm.Configure("X").Machine == sm); // Output: True

📈 DOT Graph Export

var sm = new DStateMachine<string, string>("Start");
sm.Configure("Start").OnTrigger("toEnd", tb => tb.ChangeState("End"));
sm.Configure("End").OnEntry(() => Task.CompletedTask);

string dot = sm.ExportToDot();
Console.WriteLine(dot);
// Output: DOT-format string of the state machine

🎓 Getting Started

  1. Clone the repository or add the files to your project.
  2. Create a new instance: new DStateMachine<TTrigger, TState>(initialState).
  3. Configure states using .Configure(state) and chain OnEntry, OnExit, and OnTrigger.
  4. Fire transitions using Fire(trigger) or await FireAsync(trigger).

🙌 Contributions

Pull requests and issues are welcome! If you'd like to contribute improvements or new features, feel free to fork and open a PR.


📄 License

This project is licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.4 749 3/22/2025
1.0.3 134 3/22/2025
1.0.2 131 3/22/2025
1.0.1 56 3/22/2025
1.0.0 66 3/21/2025

Release Notes Vesron 1.0.1:

Async Transition Enhancements:

Introduced asynchronous guards for transitions by converting existing synchronous guard methods to asynchronous (wrapped in Task.FromResult).

Added a new IfAsync method to support asynchronous guard conditions.

Updated all transition delegates (fixed, dynamic, and internal) to support asynchronous execution.

Async Action Support:

Added the ExecuteActionAsync method to allow asynchronous execution of side-effect actions during internal transitions.

Maintained backward compatibility by keeping the synchronous ExecuteAction method with wrapping.
           
These changes provide a flexible and robust asynchronous state machine framework while ensuring existing synchronous functionality remains intact.