Last active
          August 29, 2015 14:03 
        
      - 
      
- 
        Save hodzanassredin/7cf06a173e59ec5e7941 to your computer and use it in GitHub Desktop. 
    Simple workflow engine in csharp
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | using System; | |
| using System.Collections.Generic; | |
| using System.Linq.Expressions; | |
| using Newtonsoft.Json; | |
| using System.Reflection; | |
| using System.IO; | |
| using System.ComponentModel; | |
| using System.Globalization; | |
| namespace Tutorial1v2 | |
| { | |
| class MainClass | |
| { | |
| public class SumWorkflow:Workflow<int> | |
| { | |
| public SumWorkflow () | |
| { | |
| } | |
| public SumWorkflow (ExecutionContext context) : base (context) | |
| { | |
| } | |
| public override WorkflowStep<int> GetResultInt () | |
| { | |
| return from a in Ask<int> ("enter a") | |
| from b in Ask<int> ("enter b") | |
| let res = a + b | |
| from x in Show ("Result= " + res) | |
| select res; | |
| } | |
| } | |
| public class WorkflowComposition:Workflow<int> | |
| { | |
| public override WorkflowStep<int> GetResultInt () | |
| { | |
| return from a in new SumWorkflow (Context).GetResult () | |
| from b in new SumWorkflow (Context).GetResult () | |
| let res = a + b | |
| from v in Show ("Result of two = " + (a + b)) | |
| select a + b; | |
| } | |
| } | |
| public static void Main (string[] args) | |
| { | |
| var fileName = "workflow.json"; | |
| var wrkfl = Storage.Load<WorkflowComposition> (fileName); | |
| Console.WriteLine ("Current workflow state"); | |
| foreach (var item in wrkfl.Context.Memory) { | |
| Console.WriteLine (item); | |
| } | |
| var res = wrkfl.GetResult (); | |
| if (res.IsExecuted ()) { | |
| Console.WriteLine ("Finished"); | |
| File.Delete (fileName); | |
| } else { | |
| if (res.Action is Show) { | |
| Console.WriteLine ((res.Action as Show).What); | |
| wrkfl.AddResult (Unit.Value); | |
| } else if (res.Action is Ask<int>) { | |
| Console.WriteLine ((res.Action as Ask<int>).What); | |
| var resp = Console.ReadLine (); | |
| var val = int.Parse (resp); | |
| wrkfl.AddResult (val); | |
| } | |
| Storage.Save (wrkfl, fileName); | |
| } | |
| } | |
| } | |
| public static class WorkflowMonad | |
| { | |
| public static WorkflowStep<T> Return<T> (this T value) | |
| { | |
| return new WorkflowStep<T> (value); | |
| } | |
| public static WorkflowStep<U> Bind<T, U> (this WorkflowStep<T> m, Func<T, WorkflowStep<U>> k) | |
| { | |
| if (m.IsExecuted ()) { | |
| return k (m.GetValue ()); | |
| } | |
| return new WorkflowStep<U> (m.Action, m.Context, m.Index); | |
| } | |
| public static WorkflowStep<V> SelectMany<T, U, V> ( | |
| this WorkflowStep<T> id, | |
| Func<T, WorkflowStep<U>> k, | |
| Func<T, U, V> s) | |
| { | |
| return id.Bind (x => k (x).Bind (y => s (x, y).Return ())); | |
| } | |
| public static WorkflowStep<B> Select<A, B> (this WorkflowStep<A> a, Func<A, B> select) | |
| { | |
| return a.Bind (aval => WorkflowMonad.Return (select (aval))); | |
| } | |
| } | |
| public class ExecutionContext | |
| { | |
| public ExecutionContext () | |
| { | |
| Memory = new List<string> (); | |
| } | |
| public List<string> Memory { | |
| get; | |
| set; | |
| } | |
| public int Index { | |
| get; | |
| private set; | |
| } | |
| public void ClearIndex () | |
| { | |
| Index = 0; | |
| } | |
| public void Inc () | |
| { | |
| Index = Index + 1; | |
| } | |
| } | |
| public class Unit | |
| { | |
| Unit () | |
| { | |
| } | |
| public static Unit Value = new Unit (); | |
| } | |
| public class Action | |
| { | |
| } | |
| public class Show : Action | |
| { | |
| public string What { | |
| get; | |
| set; | |
| } | |
| } | |
| public class Ask<T> : Action | |
| { | |
| public string What { | |
| get; | |
| set; | |
| } | |
| } | |
| public abstract class Workflow<TB> | |
| { | |
| public Workflow () | |
| { | |
| Context = new ExecutionContext (); | |
| } | |
| public Workflow (ExecutionContext ctx) | |
| { | |
| Context = ctx; | |
| IsSubWorkflow = true; | |
| } | |
| public bool IsSubWorkflow { | |
| get; | |
| set; | |
| } | |
| public ExecutionContext Context { | |
| get; | |
| set; | |
| } | |
| protected WorkflowStep<T> Do<T> (Action act) | |
| { | |
| var step = new WorkflowStep<T> (act, Context, Context.Index); | |
| Context.Inc (); | |
| return step; | |
| } | |
| protected WorkflowStep<T> Ask<T> (String what) | |
| { | |
| return Do<T> (new Ask<T> (){ What = what }); | |
| } | |
| protected WorkflowStep<Unit> Show (String what) | |
| { | |
| return Do<Unit> (new Show (){ What = what }); | |
| } | |
| public abstract WorkflowStep<TB> GetResultInt (); | |
| public WorkflowStep<TB> GetResult () | |
| { | |
| if (!IsSubWorkflow) | |
| Context.ClearIndex (); | |
| return GetResultInt (); | |
| } | |
| public void AddResult (object val) | |
| { | |
| Context.Memory.Add (val.ValueToString ()); | |
| } | |
| } | |
| public class WorkflowStep<T> | |
| { | |
| public WorkflowStep (Action act, ExecutionContext context, int index) | |
| { | |
| Action = act; | |
| Context = context; | |
| Index = index; | |
| } | |
| public WorkflowStep (T value) | |
| { | |
| Context.Memory.Add (value.ValueToString ()); | |
| } | |
| public ExecutionContext Context = new ExecutionContext (); | |
| public Action Action { | |
| get; | |
| private set; | |
| } | |
| public bool IsExecuted () | |
| { | |
| return (this.Index) < Context.Memory.Count; | |
| } | |
| public T GetValue () | |
| { | |
| return Context.Memory [this.Index].ParseValue<T> (); | |
| } | |
| public int Index { | |
| get; | |
| set; | |
| } | |
| public WorkflowStep<TB> Bind<TB> (Func<T,WorkflowStep<TB>> f) | |
| { | |
| if (this.IsExecuted ()) { | |
| return f (this.GetValue ()); | |
| } | |
| return new WorkflowStep<TB> (this.Action, this.Context, this.Index); | |
| } | |
| public static WorkflowStep<TB> Return<TB> (TB x) | |
| { | |
| return new WorkflowStep<TB> (x); | |
| } | |
| } | |
| public static class Helpers | |
| { | |
| public static T ParseValue<T> (this string json) | |
| { | |
| return JsonConvert.DeserializeObject<T> (json); | |
| } | |
| public static string ValueToString<T> (this T value) | |
| { | |
| return JsonConvert.SerializeObject (value); | |
| } | |
| } | |
| public class Storage | |
| { | |
| static JsonSerializerSettings settings; | |
| static Storage () | |
| { | |
| settings = new JsonSerializerSettings (); | |
| } | |
| public static void Save<T> (T wrkfl, String name) | |
| { | |
| var json = JsonConvert.SerializeObject (wrkfl, settings); | |
| File.WriteAllText (name, json); | |
| } | |
| public static T Load<T> (string name) | |
| where T:new() | |
| { | |
| if (File.Exists (name)) { | |
| var json = File.ReadAllText (name); | |
| return JsonConvert.DeserializeObject<T> (json, settings); | |
| } | |
| return new T (); | |
| } | |
| } | |
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | using System; | |
| using System.Collections.Generic; | |
| using System.Linq.Expressions; | |
| using Newtonsoft.Json; | |
| using System.Reflection; | |
| using System.IO; | |
| using System.ComponentModel; | |
| namespace Tutorial1v2 | |
| { | |
| class MainClass | |
| { | |
| public abstract class Workflow<TCommand> | |
| { | |
| public Workflow () | |
| { | |
| Id = Guid.NewGuid (); | |
| } | |
| public Guid Id { | |
| get; | |
| set; | |
| } | |
| public bool IsFinished { | |
| get; | |
| set; | |
| } | |
| public int CurrentStep { | |
| get; | |
| set; | |
| } | |
| public TCommand Command { | |
| get; | |
| set; | |
| } | |
| public abstract TCommand ExecuteChild (); | |
| public void ExecuteStep () | |
| { | |
| this.Command = ExecuteChild (); | |
| this.CurrentStep = this.CurrentStep + 1; | |
| } | |
| } | |
| public interface SumCommand | |
| { | |
| } | |
| public abstract class Ask: SumCommand | |
| { | |
| public string _what; | |
| public abstract void SetResult (SumWorkflow wrkfl, int val); | |
| public Ask (string what) | |
| { | |
| _what = what; | |
| } | |
| } | |
| public class AskA: Ask | |
| { | |
| public override void SetResult (SumWorkflow wrkfl, int val) | |
| { | |
| wrkfl.A = val; | |
| } | |
| public AskA (string what) : base (what) | |
| { | |
| } | |
| } | |
| public class AskB: Ask | |
| { | |
| public override void SetResult (SumWorkflow wrkfl, int val) | |
| { | |
| wrkfl.B = val; | |
| } | |
| public AskB (string what) : base (what) | |
| { | |
| } | |
| } | |
| public class Show: SumCommand | |
| { | |
| public string _what; | |
| public Show (string what) | |
| { | |
| _what = what; | |
| } | |
| } | |
| public class SumWorkflow : Workflow<SumCommand> | |
| { | |
| public string UserInput { | |
| get; | |
| set; | |
| } | |
| public int A { | |
| get; | |
| set; | |
| } | |
| public int B { | |
| get; | |
| set; | |
| } | |
| public override SumCommand ExecuteChild () | |
| { | |
| if (CurrentStep == 0) { | |
| return new AskA ("Enter a"); | |
| } else if (CurrentStep == 1) { | |
| return new AskB ("Enter b"); | |
| } else { | |
| return new Show ("Result=" + (A + B)); | |
| } | |
| } | |
| } | |
| public class Cache | |
| { | |
| static JsonSerializerSettings settings; | |
| static Cache () | |
| { | |
| settings = new JsonSerializerSettings (); | |
| } | |
| public static void Save<T> (T wrkfl, Guid id) | |
| { | |
| var json = JsonConvert.SerializeObject (wrkfl, settings); | |
| File.WriteAllText (id + ".wrkfl", json); | |
| } | |
| public static T Load<T> (Guid id) | |
| { | |
| var json = File.ReadAllText (id + ".wrkfl"); | |
| return JsonConvert.DeserializeObject<T> (json, settings); | |
| } | |
| } | |
| public static void Main (string[] args) | |
| { | |
| Guid id = args.Length > 0 ? Guid.Parse (args [0]) : Guid.Empty; | |
| var wrkfl = id == Guid.Empty ? new SumWorkflow () : Cache.Load<SumWorkflow> (id); | |
| wrkfl.ExecuteStep (); | |
| if (wrkfl.Command is Ask) { | |
| var cmd = wrkfl.Command as Ask; | |
| Console.WriteLine (cmd._what); | |
| cmd.SetResult (wrkfl, int.Parse (Console.ReadLine ())); | |
| } | |
| if (wrkfl.Command is Show) { | |
| var cmd = wrkfl.Command as Show; | |
| Console.WriteLine (cmd._what); | |
| } | |
| if (wrkfl.IsFinished) | |
| Console.WriteLine ("Finished"); | |
| else { | |
| Console.WriteLine ("Next id = " + wrkfl.Id); | |
| Cache.Save (wrkfl, wrkfl.Id); | |
| } | |
| Console.ReadKey (); | |
| } | |
| } | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment