Skip to content

Commit ddbe91a

Browse files
author
Nilay Vishwakarma
committed
fix example
1 parent d65af93 commit ddbe91a

File tree

2 files changed

+179
-76
lines changed

2 files changed

+179
-76
lines changed

README.md

Lines changed: 106 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,55 +23,134 @@ dotnet add package FsmNet
2323

2424
## Quick Start
2525

26+
Let's define a state machine first
27+
28+
```mermaid
29+
stateDiagram-v2
30+
[*] --> Created
31+
Created --> Paid: PaymentReceived
32+
Paid --> Packed: PackingComplete
33+
Packed --> Shipped: Shipped
34+
Shipped --> Delivered: Delivered
35+
Delivered --> Returned: ReturnRequested
36+
37+
Created --> Cancelled: CancelRequested
38+
Paid --> Cancelled: CancelRequested
39+
Packed --> Cancelled: CancelRequested
40+
Shipped --> Cancelled: CancelRequested
41+
42+
Cancelled --> [*]
43+
Delivered --> [*]
44+
Returned --> [*]
45+
46+
```
47+
2648
1. Define States and Context
49+
2750
```csharp
28-
public class TicketContext
51+
public enum OrderState
2952
{
30-
public bool IsAgentAssigned { get; set; }
31-
public bool IsCustomerConfirmed { get; set; }
53+
Created,
54+
Paid,
55+
Packed,
56+
Shipped,
57+
Delivered,
58+
Cancelled,
59+
Returned
3260
}
3361

34-
public enum TicketState
62+
public class OrderContext
3563
{
36-
Open,
37-
InProgress,
38-
Resolved,
39-
Closed
64+
// This class can contain direct access to your data stores
65+
// ex: connect to your database to do complex calculations
66+
public bool PaymentReceived { get; set; }
67+
public bool PackingComplete { get; set; }
68+
public bool Shipped { get; set; }
69+
public bool Delivered { get; set; }
70+
public bool CancelRequested { get; set; }
71+
public bool ReturnRequested { get; set; }
4072
}
4173
```
4274

43-
2. Build a State Machine
44-
75+
2. Register Conditions and Side Effects
4576
```csharp
4677
using FsmNet;
4778

48-
var registry = new TransitionRegistry<TicketContext>();
49-
registry.RegisterCondition("HasAgent", ctx => ctx.IsAgentAssigned);
50-
registry.RegisterCondition("Confirmed", ctx => ctx.IsCustomerConfirmed);
51-
registry.RegisterSideEffect("NotifyCustomer", ctx => ctx.IsCustomerConfirmed = true);
79+
var registry = new TransitionRegistry<OrderContext>();
80+
registry.RegisterCondition("PaymentReceived", ctx => ctx.PaymentReceived);
81+
registry.RegisterCondition("PackingComplete", ctx => ctx.PackingComplete);
82+
registry.RegisterCondition("Shipped", ctx => ctx.Shipped);
83+
registry.RegisterCondition("Delivered", ctx => ctx.Delivered);
84+
registry.RegisterCondition("CancelRequested", ctx => ctx.CancelRequested);
85+
registry.RegisterCondition("ReturnRequested", ctx => ctx.ReturnRequested);
86+
87+
registry.RegisterSideEffect("NotifyShipment", ctx => Console.WriteLine("Customer notified: Order shipped"));
88+
registry.RegisterSideEffect("NotifyDelivery", ctx => Console.WriteLine("Customer notified: Order delivered"));
89+
registry.RegisterSideEffect("NotifyCancel", ctx => Console.WriteLine("Customer notified: Order cancelled"));
90+
registry.RegisterSideEffect("NotifyReturn", ctx => Console.WriteLine("Customer notified: Order returned"));
91+
```
92+
93+
3. Build a State Machine
5294

53-
var builder = FiniteStateMachineBuilder<TicketState, TicketContext>.Create("Ticket")
54-
.WithInitialState(TicketState.Open)
55-
.AddTransition(TicketState.Open, TicketState.InProgress)
56-
.When(registry.Conditions["HasAgent"], "HasAgent")
57-
.WithSideEffect(registry.SideEffects["NotifyCustomer"], "NotifyCustomer")
95+
```csharp
96+
var builder = FiniteStateMachineBuilder<OrderState, OrderContext>.Create("Order")
97+
.WithInitialState(OrderState.Created)
98+
.AddTransition(OrderState.Created, OrderState.Paid)
99+
.When(registry.Conditions["PaymentReceived"], "PaymentReceived")
100+
.Done()
101+
.AddTransition(OrderState.Paid, OrderState.Packed)
102+
.When(registry.Conditions["PackingComplete"], "PackingComplete")
103+
.Done()
104+
.AddTransition(OrderState.Packed, OrderState.Shipped)
105+
.When(registry.Conditions["Shipped"], "Shipped")
106+
.WithSideEffect(registry.SideEffects["NotifyShipment"], "NotifyShipment")
58107
.Done()
59-
.AddTransition(TicketState.InProgress, TicketState.Resolved)
60-
.When(registry.Conditions["Confirmed"], "Confirmed")
108+
.AddTransition(OrderState.Shipped, OrderState.Delivered)
109+
.When(registry.Conditions["Delivered"], "Delivered")
110+
.WithSideEffect(registry.SideEffects["NotifyDelivery"], "NotifyDelivery")
111+
.Done()
112+
.AddTransition(OrderState.Created, OrderState.Cancelled)
113+
.When(registry.Conditions["CancelRequested"], "CancelRequested")
114+
.WithSideEffect(registry.SideEffects["NotifyCancel"], "NotifyCancel")
115+
.Done()
116+
.AddTransition(OrderState.Paid, OrderState.Cancelled)
117+
.When(registry.Conditions["CancelRequested"], "CancelRequested")
118+
.WithSideEffect(registry.SideEffects["NotifyCancel"], "NotifyCancel")
119+
.Done()
120+
.AddTransition(OrderState.Packed, OrderState.Cancelled)
121+
.When(registry.Conditions["CancelRequested"], "CancelRequested")
122+
.WithSideEffect(registry.SideEffects["NotifyCancel"], "NotifyCancel")
123+
.Done()
124+
.AddTransition(OrderState.Shipped, OrderState.Cancelled)
125+
.When(registry.Conditions["CancelRequested"], "CancelRequested")
126+
.WithSideEffect(registry.SideEffects["NotifyCancel"], "NotifyCancel")
127+
.Done()
128+
.AddTransition(OrderState.Delivered, OrderState.Returned)
129+
.When(registry.Conditions["ReturnRequested"], "ReturnRequested")
130+
.WithSideEffect(registry.SideEffects["NotifyReturn"], "NotifyReturn")
61131
.Done();
62132

63-
var definition = builder.Build();
64-
var fsm = new FiniteStateMachine<TicketState, TicketContext>(definition);
133+
var fsm = new FiniteStateMachine<OrderState, OrderContext>(builder.Build());
134+
65135
```
66136

67137
3. Use the State Machine
68138

69139
```csharp
70-
var context = new TicketContext { IsAgentAssigned = true };
140+
var context = new OrderContext { PaymentReceived = true };
141+
fsm.TryTransitionTo(OrderState.Paid, context); // Moves to Paid
142+
143+
context.PackingComplete = true;
144+
fsm.TryTransitionTo(OrderState.Packed, context); // Moves to Packed
145+
146+
context.Shipped = true;
147+
fsm.TryTransitionTo(OrderState.Shipped, context); // Moves to Shipped, notifies shipment
148+
149+
context.Delivered = true;
150+
fsm.TryTransitionTo(OrderState.Delivered, context); // Moves to Delivered, notifies delivery
71151
72-
Console.WriteLine(fsm.Current); // Open
73-
fsm.TryTransitionTo(TicketState.InProgress, context)
74-
Console.WriteLine(fsm.Current); // InProgress
152+
context.ReturnRequested = true;
153+
fsm.TryTransitionTo(OrderState.Returned, context); // Moves to Returned, notifies return
75154
```
76155

77156
## Concepts

src/FsmNet.Example/Program.cs

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -8,68 +8,92 @@ class Program
88
{
99
static void Main()
1010
{
11-
var registry = new TransitionRegistry<TicketContext>();
12-
registry.RegisterCondition("HasAgent", ctx => ctx.IsAgentAssigned);
13-
registry.RegisterCondition("Confirmed", ctx => ctx.IsCustomerConfirmed);
14-
registry.RegisterSideEffect("NotifyCustomer", ctx => Console.WriteLine("Customer notified"));
15-
16-
var builder = FiniteStateMachineBuilder<TicketState, TicketContext>.Create("Ticket")
17-
.WithInitialState(TicketState.Open)
18-
.AddTransition(TicketState.Open, TicketState.InProgress)
19-
.When(registry.Conditions["HasAgent"], "HasAgent")
20-
.WithSideEffect(registry.SideEffects["NotifyCustomer"], "NotifyCustomer")
11+
var registry = new TransitionRegistry<OrderContext>();
12+
registry.RegisterCondition("PaymentReceived", ctx => ctx.PaymentReceived);
13+
registry.RegisterCondition("PackingComplete", ctx => ctx.PackingComplete);
14+
registry.RegisterCondition("Shipped", ctx => ctx.Shipped);
15+
registry.RegisterCondition("Delivered", ctx => ctx.Delivered);
16+
registry.RegisterCondition("CancelRequested", ctx => ctx.CancelRequested);
17+
registry.RegisterCondition("ReturnRequested", ctx => ctx.ReturnRequested);
18+
19+
registry.RegisterSideEffect("NotifyShipment", ctx => Console.WriteLine("Customer notified: Order shipped"));
20+
registry.RegisterSideEffect("NotifyDelivery", ctx => Console.WriteLine("Customer notified: Order delivered"));
21+
registry.RegisterSideEffect("NotifyCancel", ctx => Console.WriteLine("Customer notified: Order cancelled"));
22+
registry.RegisterSideEffect("NotifyReturn", ctx => Console.WriteLine("Customer notified: Order returned"));
23+
24+
var builder = FiniteStateMachineBuilder<OrderState, OrderContext>.Create("Order")
25+
.WithInitialState(OrderState.Created)
26+
.AddTransition(OrderState.Created, OrderState.Paid)
27+
.When(registry.Conditions["PaymentReceived"], "PaymentReceived")
28+
.Done()
29+
.AddTransition(OrderState.Paid, OrderState.Packed)
30+
.When(registry.Conditions["PackingComplete"], "PackingComplete")
31+
.Done()
32+
.AddTransition(OrderState.Packed, OrderState.Shipped)
33+
.When(registry.Conditions["Shipped"], "Shipped")
34+
.WithSideEffect(registry.SideEffects["NotifyShipment"], "NotifyShipment")
35+
.Done()
36+
.AddTransition(OrderState.Shipped, OrderState.Delivered)
37+
.When(registry.Conditions["Delivered"], "Delivered")
38+
.WithSideEffect(registry.SideEffects["NotifyDelivery"], "NotifyDelivery")
39+
.Done()
40+
.AddTransition(OrderState.Created, OrderState.Cancelled)
41+
.When(registry.Conditions["CancelRequested"], "CancelRequested")
42+
.WithSideEffect(registry.SideEffects["NotifyCancel"], "NotifyCancel")
43+
.Done()
44+
.AddTransition(OrderState.Paid, OrderState.Cancelled)
45+
.When(registry.Conditions["CancelRequested"], "CancelRequested")
46+
.WithSideEffect(registry.SideEffects["NotifyCancel"], "NotifyCancel")
47+
.Done()
48+
.AddTransition(OrderState.Packed, OrderState.Cancelled)
49+
.When(registry.Conditions["CancelRequested"], "CancelRequested")
50+
.WithSideEffect(registry.SideEffects["NotifyCancel"], "NotifyCancel")
51+
.Done()
52+
.AddTransition(OrderState.Shipped, OrderState.Cancelled)
53+
.When(registry.Conditions["CancelRequested"], "CancelRequested")
54+
.WithSideEffect(registry.SideEffects["NotifyCancel"], "NotifyCancel")
2155
.Done()
22-
.AddTransition(TicketState.InProgress, TicketState.Resolved)
23-
.When(registry.Conditions["Confirmed"], "Confirmed")
56+
.AddTransition(OrderState.Delivered, OrderState.Returned)
57+
.When(registry.Conditions["ReturnRequested"], "ReturnRequested")
58+
.WithSideEffect(registry.SideEffects["NotifyReturn"], "NotifyReturn")
2459
.Done();
2560

26-
var definition = builder.Build();
27-
28-
var serializable = builder.ToSerializable();
29-
30-
// JSON using System.Text.Json
31-
string json = JsonSerializer.Serialize(serializable, new JsonSerializerOptions { WriteIndented = true });
32-
33-
// YAML using YamlDotNet
34-
var yamlSerializer = new YamlDotNet.Serialization.Serializer();
35-
string yaml = yamlSerializer.Serialize(serializable);
36-
37-
// From JSON
38-
var jsonDto = JsonSerializer.Deserialize<SerializableStateMachine>(json)!;
39-
40-
// From YAML
41-
var yamlDeserializer = new YamlDotNet.Serialization.Deserializer();
42-
var yamlDto = yamlDeserializer.Deserialize<SerializableStateMachine>(new StringReader(yaml));
43-
44-
// Rebuild FSM
45-
var loadedBuilder = FiniteStateMachineBuilder<TicketState, TicketContext>.Create(jsonDto.EntityType)
46-
.LoadFrom(jsonDto, registry);
47-
48-
var loadedFsm = loadedBuilder.Build();
61+
var fsm = new FiniteStateMachine<OrderState, OrderContext>(builder.Build());
4962

50-
// Runtime FSM Usage
51-
var sm = new FiniteStateMachine<TicketState, TicketContext>(loadedFsm);
52-
var context = new TicketContext { IsAgentAssigned = true, IsCustomerConfirmed = false };
63+
var context = new OrderContext { PaymentReceived = true };
64+
fsm.TryTransitionTo(OrderState.Paid, context); // Moves to Paid
5365

54-
Console.WriteLine($"Current: {sm.Current}"); // Open
66+
context.PackingComplete = true;
67+
fsm.TryTransitionTo(OrderState.Packed, context); // Moves to Packed
5568

56-
if (sm.TryTransitionTo(TicketState.InProgress, context))
57-
Console.WriteLine($"Now: {sm.Current}"); // InProgress
69+
context.Shipped = true;
70+
fsm.TryTransitionTo(OrderState.Shipped, context); // Moves to Shipped, notifies shipment
5871

72+
context.Delivered = true;
73+
fsm.TryTransitionTo(OrderState.Delivered, context); // Moves to Delivered, notifies delivery
5974

75+
context.ReturnRequested = true;
76+
fsm.TryTransitionTo(OrderState.Returned, context); // Moves to Returned, notifies return
6077
}
6178
}
6279

63-
public enum TicketState
80+
public enum OrderState
6481
{
65-
Open,
66-
InProgress,
67-
Resolved,
68-
Closed
82+
Created,
83+
Paid,
84+
Packed,
85+
Shipped,
86+
Delivered,
87+
Cancelled,
88+
Returned
6989
}
7090

71-
public class TicketContext
91+
public class OrderContext
7292
{
73-
public bool IsAgentAssigned { get; set; }
74-
public bool IsCustomerConfirmed { get; set; }
93+
public bool PaymentReceived { get; set; }
94+
public bool PackingComplete { get; set; }
95+
public bool Shipped { get; set; }
96+
public bool Delivered { get; set; }
97+
public bool CancelRequested { get; set; }
98+
public bool ReturnRequested { get; set; }
7599
}

0 commit comments

Comments
 (0)