SSIS Script Component FireError DNE in Current Context - c#

I am trying to add some more native error handling to an SSIS C# Script Component (in Data-Flow). Right now I force it to crash the component with 1/0 which works but is hackish.
My script does some jazz on input data, but I would like to validate it at several steps and fail the component if any validations fail. The source is a select, so i don't need to
roll back any transactions etc... but I would like the component to fail the dataflow so the dataflow component will fail and follow the error handling I prescribe in control flow.
Here is the simplist relavant snippet that is holding me up:
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
public override void PreExecute()
{
base.PreExecute();
/*
Add your code here for preprocessing or remove if not needed
*/
bool pbCancel = false;
////check Row Count>0
if (Variables.WeeklyLRrowCount == 0)
this.ComponentMetaData.FireError(-1, "", "Fails Validation due to Empty Table.", "", 0, out pbCancel);
}
public override void PostExecute()
{
base.PostExecute();
/*
Add your code here for postprocessing or remove if not needed
You can set read/write variables here, for example:
Variables.MyIntVar = 100
*/
}
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
/*
Add your code here
*/
}
}
I get the following from SSIS:
"The name 'FireError' does not exist in the current context."
Is there something I am missing here?
Thanks!

You should just move your code to the PostExecute method.

"Typically, during component design, the FireError, FireInformation, and FireWarning methods are called to provide user feedback when a component is incorrectly configured."
http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.dts.runtime.idtscomponentevents(v=sql.105).aspx
If I read this correctly this is not for runtime use in a script task, but during design time use of a custom component to indicate configuration errors.
This code from http://msdn.microsoft.com/en-us/library/ms135912(v=sql.105).aspx
may be what you want.
public override void RegisterEvents()
{
string [] parameterNames = new string[2]{"RowCount", "StartTime"};
ushort [] parameterTypes = new ushort[2]{ DtsConvert.VarTypeFromTypeCode(TypeCode.Int32), DtsConvert.VarTypeFromTypeCode(TypeCode.DateTime)};
string [] parameterDescriptions = new string[2]{"The number of rows to sort.", "The start time of the Sort operation."};
EventInfos.Add("StartingSort","Fires when the component begins sorting the rows.",false,ref parameterNames, ref paramterTypes, ref parameterDescriptions);
}
public override void ProcessInput(int inputID, PipelineBuffer buffer)
{
while (buffer.NextRow())
{
// Process buffer rows.
}
IDTSEventInfo100 eventInfo = EventInfos["StartingSort"];
object []arguments = new object[2]{buffer.RowCount, DateTime.Now };
ComponentMetaData.FireCustomEvent("StartingSort", "Beginning sort operation.", ref arguments, ComponentMetaData.Name, ref FireSortEventAgain);
}

Related

Column names are not loading correctly c# scripting in SSIS

Im new to scripting in C# using SSIS so I'm not sure why this is happening. I'm using a script component to read some files. My column names that have _ "underscore" are not showing correctly
The error code is this.
Severity Code Description Project File Line Suppression State
Error CS1061 'Output0Buffer' does not contain a definition for 'funded_amnt' and no accessible extension method 'funded_amnt' accepting a first argument of type 'Output0Buffer' could be found (are you missing a using directive or an assembly reference?)
When you add columns to a Script task, I don't know the rules off the top of my head but, there is a translation that happens between Data Flow Column Name to the available name within a script task. Given that every column with an underscore in your data flow is reported to be in error, I'm guessing that is one of the valid characters in a column name that it doesn't allow in a Buffer's field name.
If I were to guess, underscores get eliminated as every column in a script has an _IsNull property added to it and perhaps multiple underscores would complicate logic somewhere.
Given a source query of
SELECT 1 AS col1, 2 AS col_underscore_2;
I get two columns in my data flow task named col1 and col_underscore_2. Adding both to a script task
This is the resulting auto-generated definition of my input buffer (BufferWrapper.cs)
public class Input0Buffer: ScriptBuffer
{
public Input0Buffer(PipelineBuffer Buffer, int[] BufferColumnIndexes, OutputNameMap OutputMap)
: base(Buffer, BufferColumnIndexes, OutputMap)
{
}
public Int32 col1
{
get
{
return Buffer.GetInt32(BufferColumnIndexes[0]);
}
}
public bool col1_IsNull
{
get
{
return IsNull(0);
}
}
public Int32 colunderscore2
{
get
{
return Buffer.GetInt32(BufferColumnIndexes[1]);
}
}
public bool colunderscore2_IsNull
{
get
{
return IsNull(1);
}
}
new public bool NextRow()
{
return base.NextRow();
}
new public bool EndOfRowset()
{
return base.EndOfRowset();
}
}
Of note, it mangles col_underscore_2 to an internal column name of colunderscore2. If you want to see the same for your, either double click on BufferWrapper.cs in Solution Explorer or put your cursor on Input0Buffer in the public override void Input0_ProcessInputRow(Input0Buffer Row) and hit F12 (Go to Definition)
If you want to see the autogenerated columns,
I think a similar logic goes on with buffer names.
I assume you're attempting to auto generate the script task and you'll want to take that into consideration. Also, if the LendingClassRow could have a null, you'll need to have logic like
if(LendingClassRow.verification_status != null)
{
Output0Buffer.verificationstatus = LendingClassRow.verification_status
}
// This entire block is not needed as it will be the default if no value is
// assigned but I call it out here in case future readers have a need to
// muck with it
else
{
Output0Buffer.verificationstatus_IsNull = true;
}

System.Text.RegularExpressions.Regex.Replace error in C# for SSIS

I am using the below code to write a ssis package in C# and when I write this code i get an error
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using System.Text.RegularExpressions;
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
public override void PreExecute()
{
base.PreExecute();
}
public override void PostExecute()
{
base.PostExecute();
}
string toreplace = "[~!##$%^&*()_+`{};':,./<>?]";
string replacewith = "";
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
Regex reg = new Regex(toreplace);
Row.NaN = reg.Replace(Row.Na, replacewith);
}
}
The error is
The best overloaded method match for
'System.Text.RegularExpressions.Regex.Replace(string,System.Text.RegularExpressions.MatchEvaluator)' has some invalid arguments
Here Na is the input column and NaN is the output column both are varchar with special characters in Inpout column.
Exceptions:
System.ArgumentNullException
System.ArgumentOutofRangeException
This is the code in the BufferWrapper in the SSIS package
/* THIS IS AUTO-GENERATED CODE THAT WILL BE OVERWRITTEN! DO NOT EDIT!
* Microsoft SQL Server Integration Services buffer wrappers
* This module defines classes for accessing data flow buffers
* THIS IS AUTO-GENERATED CODE THAT WILL BE OVERWRITTEN! DO NOT EDIT! */
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
public class Input0Buffer: ScriptBuffer
{
public Input0Buffer(PipelineBuffer Buffer, int[] BufferColumnIndexes, OutputNameMap OutputMap)
: base(Buffer, BufferColumnIndexes, OutputMap)
{
}
public BlobColumn Na
{
get
{
return (BlobColumn)Buffer[BufferColumnIndexes[0]];
}
}
public bool Na_IsNull
{
get
{
return IsNull(0);
}
}
public Int32 NaN
{
set
{
this[1] = value;
}
}
public bool NaN_IsNull
{
set
{
if (value)
{
SetNull(1);
}
else
{
throw new InvalidOperationException("IsNull property cannot be set to False. Assign a value to the column instead.");
}
}
}
new public bool NextRow()
{
return base.NextRow();
}
new public bool EndOfRowset()
{
return base.EndOfRowset();
}
}
Data flow
Script component, input columns
Script component, actual script
Your code is mostly fine. You are not testing for the possibility that the Na column is NULL. Perhaps your source data doesn't allow for nulls and thus, no need to test.
You can improve your performance by scoping the Regex at the member level and instantiate it in your PreExecute method but that's just a performance thing. Has no bearing on the error message you are receiving.
You can see my package and the expected results. I sent 4 rows down, one with a NULL value, one that shouldn't change and two that have changes required.
My data Flow
I have updated my data flow to match the steps you are using in your chameleon question.
My Source Query
I generate 2 columns of data and 4 rows worth. The Na column, which matches your original question is of type varchar. The column Agency_Names is cast as the deprecated Text data type to match your subsequent updates.
SELECT
D.Na
, CAST(D.Na AS text) AS Agency_Names
FROM
(
SELECT 'Hello world' AS Na
UNION ALL SELECT 'man~ana'
UNION ALL SELECT 'p#$$word!'
UNION ALL SELECT NULL
) D (Na);
Data Conversion
I have added a Data Conversion Transformation after my OLE DB Source. Reflecting what you have done, I converted my Agency_Name to a data type of string [DT_STR] with a length of 50 and aliased it as "Copy of Agency_Name".
Metadata
At this point, I verify that the metadata for my data flow is of type DT_STR or DT_WSTR which are the only allowable inputs for the upcoming call to the regular expression. I confirm that Copy of Agency_Names is the expected data type.
Script Task
I assigned ReadOnly usage to the columns Na and Copy of Agency_Name and aliased the later as "AgencyNames".
I added 2 output columns: NaN which matches your original question and created AgencyNamesCleaned. These are both configured to be DT_STR, codepage 1252, length of 50.
This is the script I used.
public class ScriptMain : UserComponent
{
string toreplace = "[~!##$%^&*()_+`{};':,./<>?]";
string replacewith = "";
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
Regex reg = new Regex(toreplace);
// Test for nulls otherwise Replace will blow up
if (!Row.Na_IsNull)
{
Row.NaN = reg.Replace(Row.Na, replacewith);
}
else
{
Row.NaN_IsNull = true;
}
if (!Row.AgencyNames_IsNull)
{
Row.AgencyNamesCleaned = reg.Replace(Row.AgencyNames, replacewith);
}
else
{
Row.AgencyNamesCleaned_IsNull = true;
}
}
}
Root cause analysis
I think your core issue may be is that the Na column you have isn't a string compatible type. Sriram's comment is spot on. If I look at the autogenerated code for the column Na, in my example I see
public String Na
{
get
{
return Buffer.GetString(BufferColumnIndexes[0]);
}
}
public bool Na_IsNull
{
get
{
return IsNull(0);
}
}
Your source system has provided metadata such that SSIS thinks this column is binary data. Perhaps it's NTEXT/TEXT or n/varchar(max) in the host. You need to do something to make it a compatible operand for the regular expression. I would clean up the column type in the source but if that's not an option, use a Data Conversion transformation to make it into a DT_STR/DT_WSTR type.
Denouement
You can observe in the Data Viewer, attached to my first image, that NaN and AgencyNamesCleaned have correctly stripped the offending characters. Furthermore, you can observe that my Script Task does not have a red X attached to it as your does. This indicates the script is in an invalid state.
As you had created the "Copy of Agency_Names" column from the Data Conversion Component as DT_TEXT, wired it up to the Script Component, and then changed the data type in the Data Conversion Component, the Red X on your script might be resolved by having the transformation refresh its metadata. Open the script and click recompile (ctrl-shift-b) for good measure.
There should be no underlines in your reg.Replace(... code. If there is, there is another facet to your problem that has not been communicated. My best advice at that point would be to recreate a proof of concept package, exactly as I have described and if that works, it becomes an exercise in finding the difference between what you have working and what you do not have working.

set filepath from database in SSIS variable for logging

I have some paths in my database table like this:
ID PATHXML PATHPICT PATHSONG
1 D:\XML\Here D:\Picture\Image D:\Blur\Song2
2 D:\XML\File D:\Picture\X-Files D:\IRONMAIDEN\Fearofthedark
I want to switch on logging in SSIS and save this log result to PathSong eg. D:\Blur\Song2\eventlog.log
I created a variable to get this path. But when I create an expression using this variable, it doesn't work. So what can I do to fix this?
Accessing package variables in a Script Component (of a Data Flow Task) is not the same as accessing package variables in a Script Task. For a Script Component, you first need to open the Script Transformation Editor (right-click on the component and select "Edit..."). In the Custom Properties section of the Script tab, you can enter (or select) the properties you want to make available to the script, either on a read-only or read-write basis:
Then, within the script itself, the variables will be available as strongly-typed properties of the Variables object:
// Modify as necessary
public override void PreExecute()
{
base.PreExecute();
string thePath = Variables.FilePath;
// Do something ...
}
public override void PostExecute()
{
base.PostExecute();
string theNewValue = "";
// Do something to figure out the new value...
Variables.FilePath = theNewValue;
}
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
string thePath = Variables.FilePath;
// Do whatever needs doing here ...
}
One important caveat: if you need to write to a package variable, you can only do so in the PostExecute() method.
Regarding the code snippet:
IDTSVariables100 varCollection = null;
this.VariableDispenser.LockForRead("User::FilePath");
string XlsFile;
XlsFile = varCollection["User::FilePath"].Value.ToString();
varCollection is initialized to null and never set to a valid value. Thus, any attempt to dereference it will fail.

Separating Logging Code from C# Objects

Currently I have a custom built static logging class in C# that can be called with the following code:
EventLogger.Log(EventLogger.EventType.Application, string.Format("AddData request from {0}", ipAddress));
When this is called it simply writes to a defined log file specified in a configuration file.
However, being that I have to log many, many events, my code is starting to become hard to read because all of the logging messages.
Is there an established way to more or less separate logging code from objects and methods in a C# class so code doesn't become unruly?
Thank you all in advance for your help as this is something I have been struggling with lately.
I like the AOP Features, that PostSharp offers. In my opinion Loggin is an aspect of any kind of software. Logging isn't the main value an application should provide.
So in my case, PostSharp always was fine. Spring.NET has also an AOP module which could be used to achieve this.
The most commonly used technique I have seen employs AOP in one form or another.
PostSharp is one product that does IL weaving as a form of AOP, though not the only way to do AOP in .NET.
A solution to this is to use Aspect-oriented programming in which you can separate these concerns. This is a pretty complex/invasive change though, so I'm not sure if it's feasible in your situation.
I used to have a custom built logger but recently changed to TracerX. This provides a simple way to instrument the code with different levels of severity. Loggers can be created with names closely related to the class etc that you are working with
It has a separate Viewer with a lot of filtering capabilities including logger, severity and so on.
http://tracerx.codeplex.com/
There is an article on it here: http://www.codeproject.com/KB/dotnet/TracerX.aspx
If your primary goal is to log function entry/exit points and occasional information in between, I've had good results with an Disposable logging object where the constructor traces the function entry, and Dispose() traces the exit. This allows calling code to simply wrap each method's code inside a single using statement. Methods are also provided for arbitrary logs in between. Here is a complete C# ETW event tracing class along with a function entry/exit wrapper:
using System;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace MyExample
{
// This class traces function entry/exit
// Constructor is used to automatically log function entry.
// Dispose is used to automatically log function exit.
// use "using(FnTraceWrap x = new FnTraceWrap()){ function code }" pattern for function entry/exit tracing
public class FnTraceWrap : IDisposable
{
string methodName;
string className;
private bool _disposed = false;
public FnTraceWrap()
{
StackFrame frame;
MethodBase method;
frame = new StackFrame(1);
method = frame.GetMethod();
this.methodName = method.Name;
this.className = method.DeclaringType.Name;
MyEventSourceClass.Log.TraceEnter(this.className, this.methodName);
}
public void TraceMessage(string format, params object[] args)
{
string message = String.Format(format, args);
MyEventSourceClass.Log.TraceMessage(message);
}
public void Dispose()
{
if (!this._disposed)
{
this._disposed = true;
MyEventSourceClass.Log.TraceExit(this.className, this.methodName);
}
}
}
[EventSource(Name = "MyEventSource")]
sealed class MyEventSourceClass : EventSource
{
// Global singleton instance
public static MyEventSourceClass Log = new MyEventSourceClass();
private MyEventSourceClass()
{
}
[Event(1, Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
public void TraceMessage(string message)
{
WriteEvent(1, message);
}
[Event(2, Message = "{0}({1}) - {2}: {3}", Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
public void TraceCodeLine([CallerFilePath] string filePath = "",
[CallerLineNumber] int line = 0,
[CallerMemberName] string memberName = "", string message = "")
{
WriteEvent(2, filePath, line, memberName, message);
}
// Function-level entry and exit tracing
[Event(3, Message = "Entering {0}.{1}", Opcode = EventOpcode.Start, Level = EventLevel.Informational)]
public void TraceEnter(string className, string methodName)
{
WriteEvent(3, className, methodName);
}
[Event(4, Message = "Exiting {0}.{1}", Opcode = EventOpcode.Stop, Level = EventLevel.Informational)]
public void TraceExit(string className, string methodName)
{
WriteEvent(4, className, methodName);
}
}
}
Code that uses it will look something like this:
public void DoWork(string foo)
{
using (FnTraceWrap fnTrace = new FnTraceWrap())
{
fnTrace.TraceMessage("Doing work on {0}.", foo);
/*
code ...
*/
}
}
To make the code readable, only log what you really need to (info/warning/error). Log debug messages during development, but remove most when you are finished. For trace logging, use
AOP to log simple things like method entry/exit (if you feel you need that kind of granularity).
Example:
public int SomeMethod(int arg)
{
Log.Trace("SomeClass.SomeMethod({0}), entering",arg); // A
if (arg < 0)
{
arg = -arg;
Log.Warn("Negative arg {0} was corrected", arg); // B
}
Log.Trace("SomeClass.SomeMethod({0}), returning.",arg); // C
return 2*arg;
}
In this example, the only necessary log statement is B. The log statements A and C are boilerplate, logging that you can leave to PostSharp to insert for you instead.
Also: in your example you can see that there is some form of "Action X invoked by Y", which suggests that a lot of your code could in fact be moved up to a higher level (e.g. Command/Filter).
Your proliferation of logging statements could be telling you something: that some form of design pattern could be used, which could also centralize a lot of the logging.
void DoSomething(Command command, User user)
{
Log.Info("Command {0} invoked by {1}", command, user);
command.Process(user);
}
I think it is a good option to implement something similar to filters in ASP.NET MVC. This is implement with the help of attributes and reflection. You mark every method you want to log in a certain way and enjoy. I suppose there might be a better way to do it, may be with the help of Observer pattern or something but as long as I thought about it I couldn't think of something better.
Basically such problems are called cross-cutting concerns and can be tackled with the help of AOP.
I also think that some interesting inheritance schema can be applied with log entities at the base but I would go for filters

Simple state machine example in C#?

Update:
Again thanks for the examples, they have been very helpful and with the following, I don't mean
to take anything away from them.
Aren't the currently given examples, as far as I understand them & state-machines, only half of what we usually understand by a state-machine?
In the sense that the examples do change state but that's only represented by changing the value of a variable (and allowing different value- changes in different states), while usually, a state machine should also change its behavior, and behavior not (only) in the sense of allowing different value changes for a variable depending on the state, but in the sense of allowing different methods to be executed for different states.
Or do I have a misconception of state machines and their common use?
Original question:
I found this discussion about state machines & iterator blocks in c# and tools to create state machines and whatnot for C#, so I found a lot of abstract stuff but as a noob, all of this is a little confusing.
So it would be great if someone could provide a C# source code-example that realizes a simple state machine with perhaps 3,4 states, just to get the gist of it.
Let's start with this simple state diagram:
We have:
4 states (Inactive, Active, Paused, and Exited)
5 types of state transitions (Begin Command, End Command, Pause Command, Resume Command, Exit Command).
You can convert this to C# in a handful of ways, such as performing a switch statement on the current state and command, or looking up transitions in a transition table. For this simple state machine, I prefer a transition table, which is very easy to represent using a Dictionary:
using System;
using System.Collections.Generic;
namespace Juliet
{
public enum ProcessState
{
Inactive,
Active,
Paused,
Terminated
}
public enum Command
{
Begin,
End,
Pause,
Resume,
Exit
}
public class Process
{
class StateTransition
{
readonly ProcessState CurrentState;
readonly Command Command;
public StateTransition(ProcessState currentState, Command command)
{
CurrentState = currentState;
Command = command;
}
public override int GetHashCode()
{
return 17 + 31 * CurrentState.GetHashCode() + 31 * Command.GetHashCode();
}
public override bool Equals(object obj)
{
StateTransition other = obj as StateTransition;
return other != null && this.CurrentState == other.CurrentState && this.Command == other.Command;
}
}
Dictionary<StateTransition, ProcessState> transitions;
public ProcessState CurrentState { get; private set; }
public Process()
{
CurrentState = ProcessState.Inactive;
transitions = new Dictionary<StateTransition, ProcessState>
{
{ new StateTransition(ProcessState.Inactive, Command.Exit), ProcessState.Terminated },
{ new StateTransition(ProcessState.Inactive, Command.Begin), ProcessState.Active },
{ new StateTransition(ProcessState.Active, Command.End), ProcessState.Inactive },
{ new StateTransition(ProcessState.Active, Command.Pause), ProcessState.Paused },
{ new StateTransition(ProcessState.Paused, Command.End), ProcessState.Inactive },
{ new StateTransition(ProcessState.Paused, Command.Resume), ProcessState.Active }
};
}
public ProcessState GetNext(Command command)
{
StateTransition transition = new StateTransition(CurrentState, command);
ProcessState nextState;
if (!transitions.TryGetValue(transition, out nextState))
throw new Exception("Invalid transition: " + CurrentState + " -> " + command);
return nextState;
}
public ProcessState MoveNext(Command command)
{
CurrentState = GetNext(command);
return CurrentState;
}
}
public class Program
{
static void Main(string[] args)
{
Process p = new Process();
Console.WriteLine("Current State = " + p.CurrentState);
Console.WriteLine("Command.Begin: Current State = " + p.MoveNext(Command.Begin));
Console.WriteLine("Command.Pause: Current State = " + p.MoveNext(Command.Pause));
Console.WriteLine("Command.End: Current State = " + p.MoveNext(Command.End));
Console.WriteLine("Command.Exit: Current State = " + p.MoveNext(Command.Exit));
Console.ReadLine();
}
}
}
As a matter of personal preference, I like to design my state machines with a GetNext function to return the next state deterministically, and a MoveNext function to mutate the state machine.
You might want to use one of the existing open source Finite State Machines. E.g. bbv.Common.StateMachine found at http://code.google.com/p/bbvcommon/wiki/StateMachine. It has a very intuitive fluent syntax and a lot of features such as, enter/exit actions, transition actions, guards, hierarchical, passive implementation (executed on the thread of the caller) and active implementation (own thread on which the fsm runs, events are added to a queue).
Taking Juliets example the definition for the state machine gets very easy:
var fsm = new PassiveStateMachine<ProcessState, Command>();
fsm.In(ProcessState.Inactive)
.On(Command.Exit).Goto(ProcessState.Terminated).Execute(SomeTransitionAction)
.On(Command.Begin).Goto(ProcessState.Active);
fsm.In(ProcessState.Active)
.ExecuteOnEntry(SomeEntryAction)
.ExecuteOnExit(SomeExitAction)
.On(Command.End).Goto(ProcessState.Inactive)
.On(Command.Pause).Goto(ProcessState.Paused);
fsm.In(ProcessState.Paused)
.On(Command.End).Goto(ProcessState.Inactive).OnlyIf(SomeGuard)
.On(Command.Resume).Goto(ProcessState.Active);
fsm.Initialize(ProcessState.Inactive);
fsm.Start();
fsm.Fire(Command.Begin);
Update: The project location has moved to: https://github.com/appccelerate/statemachine
Here's an example of a very classic finite state machine, modelling a very simplified electronic device (like a TV)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace fsm
{
class Program
{
static void Main(string[] args)
{
var fsm = new FiniteStateMachine();
Console.WriteLine(fsm.State);
fsm.ProcessEvent(FiniteStateMachine.Events.PlugIn);
Console.WriteLine(fsm.State);
fsm.ProcessEvent(FiniteStateMachine.Events.TurnOn);
Console.WriteLine(fsm.State);
fsm.ProcessEvent(FiniteStateMachine.Events.TurnOff);
Console.WriteLine(fsm.State);
fsm.ProcessEvent(FiniteStateMachine.Events.TurnOn);
Console.WriteLine(fsm.State);
fsm.ProcessEvent(FiniteStateMachine.Events.RemovePower);
Console.WriteLine(fsm.State);
Console.ReadKey();
}
class FiniteStateMachine
{
public enum States { Start, Standby, On };
public States State { get; set; }
public enum Events { PlugIn, TurnOn, TurnOff, RemovePower };
private Action[,] fsm;
public FiniteStateMachine()
{
this.fsm = new Action[3, 4] {
//PlugIn, TurnOn, TurnOff, RemovePower
{this.PowerOn, null, null, null}, //start
{null, this.StandbyWhenOff, null, this.PowerOff}, //standby
{null, null, this.StandbyWhenOn, this.PowerOff} }; //on
}
public void ProcessEvent(Events theEvent)
{
this.fsm[(int)this.State, (int)theEvent].Invoke();
}
private void PowerOn() { this.State = States.Standby; }
private void PowerOff() { this.State = States.Start; }
private void StandbyWhenOn() { this.State = States.Standby; }
private void StandbyWhenOff() { this.State = States.On; }
}
}
}
Some shameless self-promo here, but a while ago I created a library called YieldMachine which allows a limited-complexity state machine to be described in a very clean and simple way. For example, consider a lamp:
Notice that this state machine has 2 triggers and 3 states. In YieldMachine code, we write a single method for all state-related behavior, in which we commit the horrible atrocity of using goto for each state. A trigger becomes a property or field of type Action, decorated with an attribute called Trigger. I've commented the code of the first state and its transitions below; the next states follow the same pattern.
public class Lamp : StateMachine
{
// Triggers (or events, or actions, whatever) that our
// state machine understands.
[Trigger]
public readonly Action PressSwitch;
[Trigger]
public readonly Action GotError;
// Actual state machine logic
protected override IEnumerable WalkStates()
{
off:
Console.WriteLine("off.");
yield return null;
if (Trigger == PressSwitch) goto on;
InvalidTrigger();
on:
Console.WriteLine("*shiiine!*");
yield return null;
if (Trigger == GotError) goto error;
if (Trigger == PressSwitch) goto off;
InvalidTrigger();
error:
Console.WriteLine("-err-");
yield return null;
if (Trigger == PressSwitch) goto off;
InvalidTrigger();
}
}
Short and nice, eh!
This state machine is controlled simply by sending triggers to it:
var sm = new Lamp();
sm.PressSwitch(); //go on
sm.PressSwitch(); //go off
sm.PressSwitch(); //go on
sm.GotError(); //get error
sm.PressSwitch(); //go off
Just to clarify, I've added some comments to the first state to help you understand how to use this.
protected override IEnumerable WalkStates()
{
off: // Each goto label is a state
Console.WriteLine("off."); // State entry actions
yield return null; // This means "Wait until a
// trigger is called"
// Ah, we got triggered!
// perform state exit actions
// (none, in this case)
if (Trigger == PressSwitch) goto on; // Transitions go here:
// depending on the trigger
// that was called, go to
// the right state
InvalidTrigger(); // Throw exception on
// invalid trigger
...
This works because the C# compiler actually created a state machine internally for each method that uses yield return. This construct is usually used to lazily create sequences of data, but in this case we're not actually interested in the returned sequence (which is all nulls anyway), but in the state behaviour that gets created under the hood.
The StateMachine base class does some reflection on construction to assign code to each [Trigger] action, which sets the Trigger member and moves the state machine forward.
But you don't really need to understand the internals to be able to use it.
You can code an iterator block that lets you execute a code block in an orchestrated fashion. How the code block is broken up really doesn't have to correspond to anything, it's just how you want to code it. For example:
IEnumerable<int> CountToTen()
{
System.Console.WriteLine("1");
yield return 0;
System.Console.WriteLine("2");
System.Console.WriteLine("3");
System.Console.WriteLine("4");
yield return 0;
System.Console.WriteLine("5");
System.Console.WriteLine("6");
System.Console.WriteLine("7");
yield return 0;
System.Console.WriteLine("8");
yield return 0;
System.Console.WriteLine("9");
System.Console.WriteLine("10");
}
In this case, when you call CountToTen, nothing actually executes, yet. What you get is effectively a state machine generator, for which you can create a new instance of the state machine. You do this by calling GetEnumerator(). The resulting IEnumerator is effectively a state machine that you can drive by calling MoveNext(...).
Thus, in this example, the first time you call MoveNext(...) you will see "1" written to the console, and the next time you call MoveNext(...) you will see 2, 3, 4, and then 5, 6, 7 and then 8, and then 9, 10. As you can see, it's a useful mechanism for orchestrating how things should occur.
It's useful to remember that state machines are an abstraction, and you don't need particular tools to create one, however tools can be useful.
You can for example realise a state machine with functions:
void Hunt(IList<Gull> gulls)
{
if (gulls.Empty())
return;
var target = gulls.First();
TargetAcquired(target, gulls);
}
void TargetAcquired(Gull target, IList<Gull> gulls)
{
var balloon = new WaterBalloon(weightKg: 20);
this.Cannon.Fire(balloon);
if (balloon.Hit)
{
TargetHit(target, gulls);
}
else
TargetMissed(target, gulls);
}
void TargetHit(Gull target, IList<Gull> gulls)
{
Console.WriteLine("Suck on it {0}!", target.Name);
Hunt(gulls);
}
void TargetMissed(Gull target, IList<Gull> gulls)
{
Console.WriteLine("I'll get ya!");
TargetAcquired(target, gulls);
}
This machine would hunt for gulls and try to hit them with water balloons. If it misses it will try firing one until it hits (could do with some realistic expectations ;)), otherwise it will gloat in the console. It continues to hunt until it's out of gulls to harass.
Each function corresponds to each state; the start and end (or accept) states are not shown. There are probably more states in there than modelled by the functions though. For example after firing the balloon the machine is really in another state than it was before it, but I decided this distinction was impractical to make.
A common way is to use classes to represent states, and then connect them in different ways.
Found this great tutorial online and it helped me wrap my head around finite state machines.
http://gamedevelopment.tutsplus.com/tutorials/finite-state-machines-theory-and-implementation--gamedev-11867
The tutorial is language agnostic, so it can easily be adapted to your C# needs.
Also, the example used (an ant looking for food) is easy to understand.
From the tutorial:
public class FSM {
private var activeState :Function; // points to the currently active state function
public function FSM() {
}
public function setState(state :Function) :void {
activeState = state;
}
public function update() :void {
if (activeState != null) {
activeState();
}
}
}
public class Ant
{
public var position :Vector3D;
public var velocity :Vector3D;
public var brain :FSM;
public function Ant(posX :Number, posY :Number) {
position = new Vector3D(posX, posY);
velocity = new Vector3D( -1, -1);
brain = new FSM();
// Tell the brain to start looking for the leaf.
brain.setState(findLeaf);
}
/**
* The "findLeaf" state.
* It makes the ant move towards the leaf.
*/
public function findLeaf() :void {
// Move the ant towards the leaf.
velocity = new Vector3D(Game.instance.leaf.x - position.x, Game.instance.leaf.y - position.y);
if (distance(Game.instance.leaf, this) <= 10) {
// The ant is extremelly close to the leaf, it's time
// to go home.
brain.setState(goHome);
}
if (distance(Game.mouse, this) <= MOUSE_THREAT_RADIUS) {
// Mouse cursor is threatening us. Let's run away!
// It will make the brain start calling runAway() from
// now on.
brain.setState(runAway);
}
}
/**
* The "goHome" state.
* It makes the ant move towards its home.
*/
public function goHome() :void {
// Move the ant towards home
velocity = new Vector3D(Game.instance.home.x - position.x, Game.instance.home.y - position.y);
if (distance(Game.instance.home, this) <= 10) {
// The ant is home, let's find the leaf again.
brain.setState(findLeaf);
}
}
/**
* The "runAway" state.
* It makes the ant run away from the mouse cursor.
*/
public function runAway() :void {
// Move the ant away from the mouse cursor
velocity = new Vector3D(position.x - Game.mouse.x, position.y - Game.mouse.y);
// Is the mouse cursor still close?
if (distance(Game.mouse, this) > MOUSE_THREAT_RADIUS) {
// No, the mouse cursor has gone away. Let's go back looking for the leaf.
brain.setState(findLeaf);
}
}
public function update():void {
// Update the FSM controlling the "brain". It will invoke the currently
// active state function: findLeaf(), goHome() or runAway().
brain.update();
// Apply the velocity vector to the position, making the ant move.
moveBasedOnVelocity();
}
(...)
}
I'm posting another answer here as this is state machines from a different perspective; very visual.
My original answer is classic imperative code. I think its quite visual as code goes because of the array which makes visualizing the state machine simple. The downside is you have to write all this. Remos's answer alleviates the effort of writing the boiler-plate code but is far less visual. There is the third alternative; really drawing the state machine.
If you are using .NET and can target version 4 of the run time then you have the option of using workflow's state machine activities. These in essence let you draw the state machine (much as in Juliet's diagram) and have the WF run-time execute it for you.
See the MSDN article Building State Machines with Windows Workflow Foundation for more details, and this CodePlex site for the latest version.
That's the option I would always prefer when targeting .NET because its easy to see, change and explain to non programmers; pictures are worth a thousand words as they say!
I haven't tried implementing a FSM in C# yet, but these all sound (or look) very complicated to the way I handled FSM's in the past in low-level languages like C or ASM.
I believe the method I've always known is called something like an "Iterative Loop". In it, you essentially have a 'while' loop that periodically exits based on events (interrupts), then returns to the main loop again.
Within the interrupt handlers, you would pass a CurrentState and return a NextState, which then overwrites the CurrentState variable in the main loop. You do this ad infinitum until the program closes (or the microcontroller resets).
What I'm seeing other answers all look very complicated compared with how a FSM is, in my mind, intended to be implemented; its beauty lies in its simplicity and FSM can be very complicated with many, many states and transitions, but they allow complicated process to be easily broken down and digested.
I realize my response shouldn't include another question, but I am forced to ask: why do these other proposed solutions appear to be so complicated?
They seem to be akin to hitting a small nail with a giant sledge hammer.
Today i deep in State Design Pattern.
I did and tested ThreadState, which equal (+/-) to Threading in C#, as described in picture from Threading in C#
You can easly add new states, configure moves from one state to other is very easy becouse it incapsulated in state implementation
Implementation and using at: Implements .NET ThreadState by State Design Pattern
I made this generic state machine out of Juliet's code. It's working awesome for me.
These are the benefits:
you can create new state machine in code with two enums TState and TCommand,
added struct TransitionResult<TState> to have more control over the output results of [Try]GetNext() methods
exposing nested class StateTransition only through AddTransition(TState, TCommand, TState) making it easier to work with it
Code:
public class StateMachine<TState, TCommand>
where TState : struct, IConvertible, IComparable
where TCommand : struct, IConvertible, IComparable
{
protected class StateTransition<TS, TC>
where TS : struct, IConvertible, IComparable
where TC : struct, IConvertible, IComparable
{
readonly TS CurrentState;
readonly TC Command;
public StateTransition(TS currentState, TC command)
{
if (!typeof(TS).IsEnum || !typeof(TC).IsEnum)
{
throw new ArgumentException("TS,TC must be an enumerated type");
}
CurrentState = currentState;
Command = command;
}
public override int GetHashCode()
{
return 17 + 31 * CurrentState.GetHashCode() + 31 * Command.GetHashCode();
}
public override bool Equals(object obj)
{
StateTransition<TS, TC> other = obj as StateTransition<TS, TC>;
return other != null
&& this.CurrentState.CompareTo(other.CurrentState) == 0
&& this.Command.CompareTo(other.Command) == 0;
}
}
private Dictionary<StateTransition<TState, TCommand>, TState> transitions;
public TState CurrentState { get; private set; }
protected StateMachine(TState initialState)
{
if (!typeof(TState).IsEnum || !typeof(TCommand).IsEnum)
{
throw new ArgumentException("TState,TCommand must be an enumerated type");
}
CurrentState = initialState;
transitions = new Dictionary<StateTransition<TState, TCommand>, TState>();
}
/// <summary>
/// Defines a new transition inside this state machine
/// </summary>
/// <param name="start">source state</param>
/// <param name="command">transition condition</param>
/// <param name="end">destination state</param>
protected void AddTransition(TState start, TCommand command, TState end)
{
transitions.Add(new StateTransition<TState, TCommand>(start, command), end);
}
public TransitionResult<TState> TryGetNext(TCommand command)
{
StateTransition<TState, TCommand> transition = new StateTransition<TState, TCommand>(CurrentState, command);
TState nextState;
if (transitions.TryGetValue(transition, out nextState))
return new TransitionResult<TState>(nextState, true);
else
return new TransitionResult<TState>(CurrentState, false);
}
public TransitionResult<TState> MoveNext(TCommand command)
{
var result = TryGetNext(command);
if(result.IsValid)
{
//changes state
CurrentState = result.NewState;
}
return result;
}
}
This is the return type of TryGetNext method:
public struct TransitionResult<TState>
{
public TransitionResult(TState newState, bool isValid)
{
NewState = newState;
IsValid = isValid;
}
public TState NewState;
public bool IsValid;
}
How to use:
This is how you can create a OnlineDiscountStateMachine from the generic class:
Define an enum OnlineDiscountState for its states and an enum OnlineDiscountCommand for its commands.
Define a class OnlineDiscountStateMachine derived from the generic class using those two enums
Derive the constructor from base(OnlineDiscountState.InitialState) so that the initial state is set to OnlineDiscountState.InitialState
Use AddTransition as many times as needed
public class OnlineDiscountStateMachine : StateMachine<OnlineDiscountState, OnlineDiscountCommand>
{
public OnlineDiscountStateMachine() : base(OnlineDiscountState.Disconnected)
{
AddTransition(OnlineDiscountState.Disconnected, OnlineDiscountCommand.Connect, OnlineDiscountState.Connected);
AddTransition(OnlineDiscountState.Disconnected, OnlineDiscountCommand.Connect, OnlineDiscountState.Error_AuthenticationError);
AddTransition(OnlineDiscountState.Connected, OnlineDiscountCommand.Submit, OnlineDiscountState.WaitingForResponse);
AddTransition(OnlineDiscountState.WaitingForResponse, OnlineDiscountCommand.DataReceived, OnlineDiscountState.Disconnected);
}
}
use the derived state machine
odsm = new OnlineDiscountStateMachine();
public void Connect()
{
var result = odsm.TryGetNext(OnlineDiscountCommand.Connect);
//is result valid?
if (!result.IsValid)
//if this happens you need to add transitions to the state machine
//in this case result.NewState is the same as before
Console.WriteLine("cannot navigate from this state using OnlineDiscountCommand.Connect");
//the transition was successfull
//show messages for new states
else if(result.NewState == OnlineDiscountState.Error_AuthenticationError)
Console.WriteLine("invalid user/pass");
else if(result.NewState == OnlineDiscountState.Connected)
Console.WriteLine("Connected");
else
Console.WriteLine("not implemented transition result for " + result.NewState);
}
Not sure whether I miss the point, but I think none of the answers here are "simple" state machines. What i usually call a simple state machine is using a loop with a switch inside. That is what we used in PLC / microchip programming or in C/C++ programming at the university.
advantages:
easy to write. no special objects and stuff required. you dont even need object orientation for it.
when it is small, it is easy to understand.
disadvantages:
can become quite big and hard to read, when there are many states.
It looked like that:
public enum State
{
First,
Second,
Third,
}
static void Main(string[] args)
{
var state = State.First;
// x and i are just examples for stuff that you could change inside the state and use for state transitions
var x = 0;
var i = 0;
// does not have to be a while loop. you could loop over the characters of a string too
while (true)
{
switch (state)
{
case State.First:
// Do sth here
if (x == 2)
state = State.Second;
// you may or may not add a break; right after setting the next state
// or do sth here
if (i == 3)
state = State.Third;
// or here
break;
case State.Second:
// Do sth here
if (x == 10)
state = State.First;
// or do sth here
break;
case State.Third:
// Do sth here
if (x == 10)
state = State.First;
// or do sth here
break;
default:
// you may wanna throw an exception here.
break;
}
}
}
if it should be really a state machine on which you call methods which react depending on which state you are in differently: state design pattern is the better approach
In my opinion a state machine is not only meant for changing states but also (very important) for handling triggers/events within a specific state. If you want to understand state machine design pattern better, a good description can be found within the book Head First Design Patterns, page 320.
It is not only about the states within variables but also about handling triggers within the different states. Great chapter (and no, there is no fee for me in mentioning this :-) which contains just an easy to understand explanation.
What a bout StatePattern. Does that fit your needs?
I think its context related, but its worth a shot for sure.
http://en.wikipedia.org/wiki/State_pattern
This let your states decide where to go and not the "object" class.
Bruno
I've just contributed this:
https://code.google.com/p/ysharp/source/browse/#svn%2Ftrunk%2FStateMachinesPoC
Here's one of the examples demoing direct and indirect sending of commands, with states as IObserver(of signal), thus responders to a signal source, IObservable(of signal):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test
{
using Machines;
public static class WatchingTvSampleAdvanced
{
// Enum type for the transition triggers (instead of System.String) :
public enum TvOperation { Plug, SwitchOn, SwitchOff, Unplug, Dispose }
// The state machine class type is also used as the type for its possible states constants :
public class Television : NamedState<Television, TvOperation, DateTime>
{
// Declare all the possible states constants :
public static readonly Television Unplugged = new Television("(Unplugged TV)");
public static readonly Television Off = new Television("(TV Off)");
public static readonly Television On = new Television("(TV On)");
public static readonly Television Disposed = new Television("(Disposed TV)");
// For convenience, enter the default start state when the parameterless constructor executes :
public Television() : this(Television.Unplugged) { }
// To create a state machine instance, with a given start state :
private Television(Television value) : this(null, value) { }
// To create a possible state constant :
private Television(string moniker) : this(moniker, null) { }
private Television(string moniker, Television value)
{
if (moniker == null)
{
// Build the state graph programmatically
// (instead of declaratively via custom attributes) :
Handler<Television, TvOperation, DateTime> stateChangeHandler = StateChange;
Build
(
new[]
{
new { From = Television.Unplugged, When = TvOperation.Plug, Goto = Television.Off, With = stateChangeHandler },
new { From = Television.Unplugged, When = TvOperation.Dispose, Goto = Television.Disposed, With = stateChangeHandler },
new { From = Television.Off, When = TvOperation.SwitchOn, Goto = Television.On, With = stateChangeHandler },
new { From = Television.Off, When = TvOperation.Unplug, Goto = Television.Unplugged, With = stateChangeHandler },
new { From = Television.Off, When = TvOperation.Dispose, Goto = Television.Disposed, With = stateChangeHandler },
new { From = Television.On, When = TvOperation.SwitchOff, Goto = Television.Off, With = stateChangeHandler },
new { From = Television.On, When = TvOperation.Unplug, Goto = Television.Unplugged, With = stateChangeHandler },
new { From = Television.On, When = TvOperation.Dispose, Goto = Television.Disposed, With = stateChangeHandler }
},
false
);
}
else
// Name the state constant :
Moniker = moniker;
Start(value ?? this);
}
// Because the states' value domain is a reference type, disallow the null value for any start state value :
protected override void OnStart(Television value)
{
if (value == null)
throw new ArgumentNullException("value", "cannot be null");
}
// When reaching a final state, unsubscribe from all the signal source(s), if any :
protected override void OnComplete(bool stateComplete)
{
// Holds during all transitions into a final state
// (i.e., stateComplete implies IsFinal) :
System.Diagnostics.Debug.Assert(!stateComplete || IsFinal);
if (stateComplete)
UnsubscribeFromAll();
}
// Executed before and after every state transition :
private void StateChange(IState<Television> state, ExecutionStep step, Television value, TvOperation info, DateTime args)
{
// Holds during all possible transitions defined in the state graph
// (i.e., (step equals ExecutionStep.LeaveState) implies (not state.IsFinal))
System.Diagnostics.Debug.Assert((step != ExecutionStep.LeaveState) || !state.IsFinal);
// Holds in instance (i.e., non-static) transition handlers like this one :
System.Diagnostics.Debug.Assert(this == state);
switch (step)
{
case ExecutionStep.LeaveState:
var timeStamp = ((args != default(DateTime)) ? String.Format("\t\t(# {0})", args) : String.Empty);
Console.WriteLine();
// 'value' is the state value that we are transitioning TO :
Console.WriteLine("\tLeave :\t{0} -- {1} -> {2}{3}", this, info, value, timeStamp);
break;
case ExecutionStep.EnterState:
// 'value' is the state value that we have transitioned FROM :
Console.WriteLine("\tEnter :\t{0} -- {1} -> {2}", value, info, this);
break;
default:
break;
}
}
public override string ToString() { return (IsConstant ? Moniker : Value.ToString()); }
}
public static void Run()
{
Console.Clear();
// Create a signal source instance (here, a.k.a. "remote control") that implements
// IObservable<TvOperation> and IObservable<KeyValuePair<TvOperation, DateTime>> :
var remote = new SignalSource<TvOperation, DateTime>();
// Create a television state machine instance (automatically set in a default start state),
// and make it subscribe to a compatible signal source, such as the remote control, precisely :
var tv = new Television().Using(remote);
bool done;
// Always holds, assuming the call to Using(...) didn't throw an exception (in case of subscription failure) :
System.Diagnostics.Debug.Assert(tv != null, "There's a bug somewhere: this message should never be displayed!");
// As commonly done, we can trigger a transition directly on the state machine :
tv.MoveNext(TvOperation.Plug, DateTime.Now);
// Alternatively, we can also trigger transitions by emitting from the signal source / remote control
// that the state machine subscribed to / is an observer of :
remote.Emit(TvOperation.SwitchOn, DateTime.Now);
remote.Emit(TvOperation.SwitchOff);
remote.Emit(TvOperation.SwitchOn);
remote.Emit(TvOperation.SwitchOff, DateTime.Now);
done =
(
tv.
MoveNext(TvOperation.Unplug).
MoveNext(TvOperation.Dispose) // MoveNext(...) returns null iff tv.IsFinal == true
== null
);
remote.Emit(TvOperation.Unplug); // Ignored by the state machine thanks to the OnComplete(...) override above
Console.WriteLine();
Console.WriteLine("Is the TV's state '{0}' a final state? {1}", tv.Value, done);
Console.WriteLine();
Console.WriteLine("Press any key...");
Console.ReadKey();
}
}
}
Note : this example is rather artificial and mostly meant to demo a number of orthogonal features. There should seldomly be a real need to implement the state value domain itself by a full blown class, using the CRTP ( see : http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern ) like this.
Here's for a certainly simpler and likely much more common implementation use case (using a simple enum type as the states value domain), for the same state machine, and with the same test case :
https://code.google.com/p/ysharp/source/browse/trunk/StateMachinesPoC/WatchingTVSample.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test
{
using Machines;
public static class WatchingTvSample
{
public enum Status { Unplugged, Off, On, Disposed }
public class DeviceTransitionAttribute : TransitionAttribute
{
public Status From { get; set; }
public string When { get; set; }
public Status Goto { get; set; }
public object With { get; set; }
}
// State<Status> is a shortcut for / derived from State<Status, string>,
// which in turn is a shortcut for / derived from State<Status, string, object> :
public class Device : State<Status>
{
// Executed before and after every state transition :
protected override void OnChange(ExecutionStep step, Status value, string info, object args)
{
if (step == ExecutionStep.EnterState)
{
// 'value' is the state value that we have transitioned FROM :
Console.WriteLine("\t{0} -- {1} -> {2}", value, info, this);
}
}
public override string ToString() { return Value.ToString(); }
}
// Since 'Device' has no state graph of its own, define one for derived 'Television' :
[DeviceTransition(From = Status.Unplugged, When = "Plug", Goto = Status.Off)]
[DeviceTransition(From = Status.Unplugged, When = "Dispose", Goto = Status.Disposed)]
[DeviceTransition(From = Status.Off, When = "Switch On", Goto = Status.On)]
[DeviceTransition(From = Status.Off, When = "Unplug", Goto = Status.Unplugged)]
[DeviceTransition(From = Status.Off, When = "Dispose", Goto = Status.Disposed)]
[DeviceTransition(From = Status.On, When = "Switch Off", Goto = Status.Off)]
[DeviceTransition(From = Status.On, When = "Unplug", Goto = Status.Unplugged)]
[DeviceTransition(From = Status.On, When = "Dispose", Goto = Status.Disposed)]
public class Television : Device { }
public static void Run()
{
Console.Clear();
// Create a television state machine instance, and return it, set in some start state :
var tv = new Television().Start(Status.Unplugged);
bool done;
// Holds iff the chosen start state isn't a final state :
System.Diagnostics.Debug.Assert(tv != null, "The chosen start state is a final state!");
// Trigger some state transitions with no arguments
// ('args' is ignored by this state machine's OnChange(...), anyway) :
done =
(
tv.
MoveNext("Plug").
MoveNext("Switch On").
MoveNext("Switch Off").
MoveNext("Switch On").
MoveNext("Switch Off").
MoveNext("Unplug").
MoveNext("Dispose") // MoveNext(...) returns null iff tv.IsFinal == true
== null
);
Console.WriteLine();
Console.WriteLine("Is the TV's state '{0}' a final state? {1}", tv.Value, done);
Console.WriteLine();
Console.WriteLine("Press any key...");
Console.ReadKey();
}
}
}
'HTH
FiniteStateMachine is a Simple State Machine, written in C# Link
Advantages tu use my library FiniteStateMachine:
Define a "context" class to present a single interface to the outside world.
Define a State abstract base class.
Represent the different "states" of the state machine as derived classes of the State base class.
Define state-specific behavior in the appropriate State derived classes.
Maintain a pointer to the current "state" in the "context" class.
To change the state of the state machine, change the current "state" pointer.
Download DLL Download
Example on LINQPad:
void Main()
{
var machine = new SFM.Machine(new StatePaused());
var output = machine.Command("Input_Start", Command.Start);
Console.WriteLine(Command.Start.ToString() + "-> State: " + machine.Current);
Console.WriteLine(output);
output = machine.Command("Input_Pause", Command.Pause);
Console.WriteLine(Command.Pause.ToString() + "-> State: " + machine.Current);
Console.WriteLine(output);
Console.WriteLine("-------------------------------------------------");
}
public enum Command
{
Start,
Pause,
}
public class StateActive : SFM.State
{
public override void Handle(SFM.IContext context)
{
//Gestione parametri
var input = (String)context.Input;
context.Output = input;
//Gestione Navigazione
if ((Command)context.Command == Command.Pause) context.Next = new StatePaused();
if ((Command)context.Command == Command.Start) context.Next = this;
}
}
public class StatePaused : SFM.State
{
public override void Handle(SFM.IContext context)
{
//Gestione parametri
var input = (String)context.Input;
context.Output = input;
//Gestione Navigazione
if ((Command)context.Command == Command.Start) context.Next = new StateActive();
if ((Command)context.Command == Command.Pause) context.Next = this;
}
}
I would recommend state.cs. I personally used state.js (the JavaScript version) and am very happy with it. That C# version works in a similar way.
You instantiate states:
// create the state machine
var player = new StateMachine<State>( "player" );
// create some states
var initial = player.CreatePseudoState( "initial", PseudoStateKind.Initial );
var operational = player.CreateCompositeState( "operational" );
...
You instantiate some transitions:
var t0 = player.CreateTransition( initial, operational );
player.CreateTransition( history, stopped );
player.CreateTransition<String>( stopped, running, ( state, command ) => command.Equals( "play" ) );
player.CreateTransition<String>( active, stopped, ( state, command ) => command.Equals( "stop" ) );
You define actions on states and transitions:
t0.Effect += DisengageHead;
t0.Effect += StopMotor;
And that's (pretty much) it. Look at the website for more information.
There are 2 popular state machine packages in NuGet.
Appccelerate.StateMachine (13.6K downloads + 3.82K of legacy version (bbv.Common.StateMachine))
StateMachineToolkit (1.56K downloads)
The Appccelerate lib has good documentation, but it does not support .NET 4, so I chose StateMachineToolkit for my project.
Other alternative in this repo https://github.com/lingkodsoft/StateBliss
used fluent syntax, supports triggers.
public class BasicTests
{
[Fact]
public void Tests()
{
// Arrange
StateMachineManager.Register(new [] { typeof(BasicTests).Assembly }); //Register at bootstrap of your application, i.e. Startup
var currentState = AuthenticationState.Unauthenticated;
var nextState = AuthenticationState.Authenticated;
var data = new Dictionary<string, object>();
// Act
var changeInfo = StateMachineManager.Trigger(currentState, nextState, data);
// Assert
Assert.True(changeInfo.StateChangedSucceeded);
Assert.Equal("ChangingHandler1", changeInfo.Data["key1"]);
Assert.Equal("ChangingHandler2", changeInfo.Data["key2"]);
}
//this class gets regitered automatically by calling StateMachineManager.Register
public class AuthenticationStateDefinition : StateDefinition<AuthenticationState>
{
public override void Define(IStateFromBuilder<AuthenticationState> builder)
{
builder.From(AuthenticationState.Unauthenticated).To(AuthenticationState.Authenticated)
.Changing(this, a => a.ChangingHandler1)
.Changed(this, a => a.ChangedHandler1);
builder.OnEntering(AuthenticationState.Authenticated, this, a => a.OnEnteringHandler1);
builder.OnEntered(AuthenticationState.Authenticated, this, a => a.OnEnteredHandler1);
builder.OnExiting(AuthenticationState.Unauthenticated, this, a => a.OnExitingHandler1);
builder.OnExited(AuthenticationState.Authenticated, this, a => a.OnExitedHandler1);
builder.OnEditing(AuthenticationState.Authenticated, this, a => a.OnEditingHandler1);
builder.OnEdited(AuthenticationState.Authenticated, this, a => a.OnEditedHandler1);
builder.ThrowExceptionWhenDiscontinued = true;
}
private void ChangingHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
{
var data = changeinfo.DataAs<Dictionary<string, object>>();
data["key1"] = "ChangingHandler1";
}
private void OnEnteringHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
{
// changeinfo.Continue = false; //this will prevent changing the state
}
private void OnEditedHandler1(StateChangeInfo<AuthenticationState> changeinfo)
{
}
private void OnExitedHandler1(StateChangeInfo<AuthenticationState> changeinfo)
{
}
private void OnEnteredHandler1(StateChangeInfo<AuthenticationState> changeinfo)
{
}
private void OnEditingHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
{
}
private void OnExitingHandler1(StateChangeGuardInfo<AuthenticationState> changeinfo)
{
}
private void ChangedHandler1(StateChangeInfo<AuthenticationState> changeinfo)
{
}
}
public class AnotherAuthenticationStateDefinition : StateDefinition<AuthenticationState>
{
public override void Define(IStateFromBuilder<AuthenticationState> builder)
{
builder.From(AuthenticationState.Unauthenticated).To(AuthenticationState.Authenticated)
.Changing(this, a => a.ChangingHandler2);
}
private void ChangingHandler2(StateChangeGuardInfo<AuthenticationState> changeinfo)
{
var data = changeinfo.DataAs<Dictionary<string, object>>();
data["key2"] = "ChangingHandler2";
}
}
}
public enum AuthenticationState
{
Unauthenticated,
Authenticated
}
}
One more state machine for the list, mine: https://github.com/IanMercer/Abodit.StateMachine
In addition to simple states with entry and exit actions, and actions on each transition, this one is designed for use in async code. It also supports hierarchical states and compound state machines. So not really 'simple' but in use it's quite easy to code states and transitions.
static OpenClosedStateMachine()
{
Closed
.When(Fridge.eDoorOpens, (m, s, e, c) => Task.FromResult(Open));
Open
.When(Fridge.eDoorCloses, (m, s, e, c) => Task.FromResult(Closed));
}
Unlike others it also supports temporal transitions so it's easy to transition to a different state After a given period or At a given time.
I too struggled with State Machines when used with a message broker like RabbitMQ or Rabbit.
I created this video to help others.
https://www.youtube.com/watch?v=Vwfngk0YhLs&t=11s&ab_channel=GarryTaylor
Code was from this Github repo
https://github.com/welhell/masstransit-saga-example
I've built a Nuget library that implements a simple and powerful state machine and injectable in DI. You can check it from here Nuget - State Machine
You can use my solution, this is the most convenient way. It’s also free.
Create state machine in three steps :
1. Create scheme in node editor🔗 and load it in your project using library📚
StateMachine stateMachine = new StateMachine("scheme.xml");
2. Describe your app logic on events⚡
stateMachine.GetState("State1").OnExit(Action1);
stateMachine.GetState("State2").OnEntry(Action2);
stateMachine.GetTransition("Transition1").OnInvoke(Action3);
stateMachine.OnChangeState(Action4);
3. Run the state machine🚘
stateMachine.Start();
Links:
Node editor: https://github.com/SimpleStateMachine/SimpleStateMachineNodeEditor
Library: https://github.com/SimpleStateMachine/SimpleStateMachineLibrary

Categories