Пример #1
0
        public JObject GetPossiblePath(Guid id, string libID)                     //审批用户获取下一步可能的路径
        {
            WorkFlowItem        cwfi  = bdb.WorkFlowItems.Where(i => i.WfInstanceId == id).FirstOrDefault();
            ItServiceItem       cisi  = bdb.ItServiceItems.Where(i => i.ID == cwfi.WfBusinessId).FirstOrDefault();
            WorkflowApplication wfApp = new WorkflowApplication(new ItService())
            {
                InstanceStore   = CreateInstanceStore(),
                PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e)
                {
                    //var ex = e.GetInstanceExtensions<CustomTrackingParticipant>();
                    // Outputs = ex.First().Outputs.ToString();
                    return(PersistableIdleAction.Unload);
                },
                Completed = delegate(WorkflowApplicationCompletedEventArgs e)
                {
                },
                Aborted = delegate(WorkflowApplicationAbortedEventArgs e)
                {
                },
                Unloaded = delegate(WorkflowApplicationEventArgs e)
                {
                },
                OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
                {
                    return(UnhandledExceptionAction.Terminate);
                },
                Idle = delegate(WorkflowApplicationIdleEventArgs e)
                {
                }
            };
            var trackerInstance = StateMachineStateTracker.LoadInstance(id, wfApp.WorkflowDefinition, ConfigurationManager.ConnectionStrings["ApacheConnection"].ConnectionString);

            //var Pt = trackerInstance.PossibleTransitions;
            var Pt = GetPossibleTransitions(libID, false, cisi.Status);

            //BookmarkResumptionResult result = wfApp.ResumeBookmark("Hello123", "ddd");
            string[] strs = Pt.Split(',');
            JObject  json = new JObject(
                new JProperty("rows",
                              new JArray(
                                  from r in strs
                                  select new JObject(
                                      new JProperty("ID", r.ToString()),
                                      new JProperty("Name", r.ToString())))));

            return(json);
        }
Пример #2
0
        static void Main(string[] args)
        {
            Activity testing = new Process81();

            WorkflowApplication app = new WorkflowApplication(testing);
            var tracker             = new StateMachineStateTracker(app.WorkflowDefinition);

            app.Extensions.Add(tracker);



            //WorkflowInvoker.Invoke(app);
            app.Run();

            Console.WriteLine(tracker.CurrentState);

            Console.ReadLine();
        }
Пример #3
0
        static AppWorkflow Create(IDbContext dbContext, Activity root, IDictionary <String, Object> args, WorkflowIdentity identity)
        {
            var aw    = new AppWorkflow();
            var store = aw.CreateInstanceStore(dbContext.ConnectionString(null));

            if (args == null)
            {
                aw._application = new WorkflowApplication(root, identity);
            }
            else
            {
                aw._application = new WorkflowApplication(root, args, identity);
            }
            aw.SetApplicationHandlers();
            aw._dbContext = dbContext;
            aw._tracker   = StateMachineStateTracker.Attach(aw._application);
            aw._application.Extensions.Add(new WorkflowTracker(aw));
            aw._application.InstanceStore = store;
            return(aw);
        }
Пример #4
0
        private static InstanceStore CreateInstanceStore()
        {
            var conn  = ConfigurationManager.ConnectionStrings["ApacheConnection"].ConnectionString;
            var store = new SqlWorkflowInstanceStore(conn)
            {
                InstanceLockedExceptionAction    = InstanceLockedExceptionAction.AggressiveRetry,
                InstanceCompletionAction         = InstanceCompletionAction.DeleteNothing,
                HostLockRenewalPeriod            = TimeSpan.FromSeconds(20),
                RunnableInstancesDetectionPeriod = TimeSpan.FromSeconds(3)
            };

            StateMachineStateTracker.Promote(store);
            var handle = store.CreateInstanceHandle();
            var view   = store.Execute(handle, new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(60));

            store.DefaultInstanceOwner = view.InstanceOwner;

            handle.Free();

            return(store);
        }
Пример #5
0
        private void InitializeStateTracker(IExtensionEnabledWorkflowApplication workflow)
        {
            StateMachineStateTracker stateTracker = new StateMachineStateTracker(taskWorkflow);
            workflow.MyExtensions.Add(stateTracker);
            workflow.MyExtensions.Add(new StateTrackerPersistenceProvider(stateTracker));

            this.stateTrackers.Add(workflow.Id, stateTracker);
        }
Пример #6
0
        public JObject CreateWorkFlow(string libID)   //起草者创建流程,并保存到微软持续化数据库中
        {
            AutoResetEvent      syncEvent     = new AutoResetEvent(false);
            string              currentUserId = User.Identity.GetUserId();
            ApplicationUser     user          = db.Users.Include(i => i.Roles).FirstOrDefault(i => i.Id == currentUserId); //获取当前用户username
            WorkFlowInParameter WfInData      = new WorkFlowInParameter();

            WfInData.drafter = user.UserName;
            Dictionary <string, object> inputs = new Dictionary <string, object>();

            inputs.Add("WfIn", WfInData);
            //var act = CreateActivityFrom(Server.MapPath("~") + "\\WorkFlow\\ItService.xaml");
            WorkflowApplication wfApp = new WorkflowApplication(new ItService(), inputs)
            {
                InstanceStore   = CreateInstanceStore(),
                PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e)
                {
                    //var ex = e.GetInstanceExtensions<CustomTrackingParticipant>();
                    //Outputs = ex.First().Outputs.ToString();
                    return(PersistableIdleAction.Unload);
                },
                Completed = delegate(WorkflowApplicationCompletedEventArgs e)
                {
                },
                Aborted = delegate(WorkflowApplicationAbortedEventArgs e)
                {
                },
                Unloaded = delegate(WorkflowApplicationEventArgs e)
                {
                    syncEvent.Set();
                },
                OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
                {
                    return(UnhandledExceptionAction.Terminate);
                },
                Idle = delegate(WorkflowApplicationIdleEventArgs e)
                {
                }
            };
            var StateTracker = new StateMachineStateTracker(wfApp.WorkflowDefinition); //当前状态追踪

            wfApp.Extensions.Add(StateTracker);
            wfApp.Extensions.Add(new StateTrackerPersistenceProvider(StateTracker));
            var cu = new CustomTrackingParticipant();         //获取Activity内部变量

            wfApp.Extensions.Add(cu);                         //获取Activity内部变量需要的追踪器
            Guid instanceId = wfApp.Id;

            //var trackerInstance = StateMachineStateTracker.LoadInstance(id, wfApp.WorkflowDefinition, ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
            wfApp.Run();
            syncEvent.WaitOne();
            //string CurrentUser = cu.Outputs["CurrentUser"].ToString();
            //var Pt = StateTracker.PossibleTransitions;
            //var CurrentState = StateTracker.CurrentState;

            //BookmarkResumptionResult result = wfApp.ResumeBookmark("Hello123", "ddd");
            var Pt = GetPossibleTransitions(libID, true, 1);

            string[] strs = Pt.Split(',');

            JObject json = new JObject(
                new JProperty("instanceId", instanceId),
                new JProperty("rows",
                              new JArray(
                                  from r in strs
                                  select new JObject(
                                      new JProperty("ID", r.ToString()),
                                      new JProperty("Name", r.ToString())))));

            return(json);
        }
Пример #7
0
        public ActionResult ToNextState(ItServiceItem isi, Guid instanceId, string NextLink, string libid, string Opinion)  //审批者到下一环节,思路:保存当前流程的数据,恢复bookmark到下一环节,并保存下一环节流程信息
        {
            #region 判断是不是当前处理人
            WorkFlowItem    cwfi          = bdb.WorkFlowItems.Where(i => i.WfInstanceId == instanceId).FirstOrDefault();
            string          currentUserId = User.Identity.GetUserId();
            ApplicationUser user          = db.Users.Include(i => i.Roles).FirstOrDefault(i => i.Id == currentUserId);
            if (cwfi.WfCurrentUser.ToString().Trim() != user.UserName.ToString().Trim())
            {
                var json = new
                {
                    errorMsg = "你不是当前处理人"
                };

                return(Json(json, "text/html", JsonRequestBehavior.AllowGet));
            }
            #endregion
            string[]            strs       = NextLink.Trim().Split('(');
            AutoResetEvent      syncEvent  = new AutoResetEvent(false);
            int                 isComplete = 0;
            WorkflowApplication wfApp      = new WorkflowApplication(new ItService())
            {
                InstanceStore   = CreateInstanceStore(),
                PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e)
                {
                    //var ex = e.GetInstanceExtensions<CustomTrackingParticipant>();
                    // Outputs = ex.First().Outputs.ToString();
                    return(PersistableIdleAction.Unload);
                },
                Completed = delegate(WorkflowApplicationCompletedEventArgs e)
                {
                    isComplete = 1;
                    syncEvent.Set();
                },
                Aborted = delegate(WorkflowApplicationAbortedEventArgs e)
                {
                },
                Unloaded = delegate(WorkflowApplicationEventArgs e)
                {
                    syncEvent.Set();
                },
                OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
                {
                    return(UnhandledExceptionAction.Terminate);
                },
                Idle = delegate(WorkflowApplicationIdleEventArgs e)
                {
                }
            };
            var StateTracker = new StateMachineStateTracker(wfApp.WorkflowDefinition); //当前状态追踪
            wfApp.Extensions.Add(StateTracker);
            wfApp.Extensions.Add(new StateTrackerPersistenceProvider(StateTracker));
            var cu = new CustomTrackingParticipant();         //获取Activity内部变量
            wfApp.Extensions.Add(cu);                         //获取Activity内部变量需要的追踪器
            //Guid instanceId = wfApp.Id;
            var trackerInstance = StateMachineStateTracker.LoadInstance(instanceId, wfApp.WorkflowDefinition, ConfigurationManager.ConnectionStrings["ApacheConnection"].ConnectionString);
            wfApp.Load(instanceId);
            BookmarkResumptionResult result = wfApp.ResumeBookmark(trackerInstance.CurrentState, strs[0]);
            //BookmarkResumptionResult result = wfApp.ResumeBookmark(trackerInstance.CurrentState, NextLink.Trim());   //恢复当前状态,并进入下一个bookmark,注意使用Trim,开始没使用,NextLInk无法取到,调试了大半夜
            syncEvent.WaitOne();

            string CurrentUser;
            string OpinionField = "";
            string CurrentState;
            string completeStr = "";

            if (isComplete == 0)
            {
                if (strs.Count() == 1)
                {
                    CurrentUser = cu.Outputs["CurrentUser"].ToString();
                }
                else
                {
                    CurrentUser = db.LibraryApprovers.ToList().First(p => (p.LibID == libid) && (p.ApproverName == strs[1].Replace(")", ""))).Approver;
                }
                OpinionField = cu.Outputs["OpinionField"].ToString();
                CurrentState = StateTracker.CurrentState;
            }
            else
            {
                CurrentUser  = "******";
                CurrentState = "已结束";
                completeStr  = "->结束";
            }
            //string currentUserId = User.Identity.GetUserId();
            //ApplicationUser user = db.Users.Include(i => i.Roles).FirstOrDefault(i => i.Id == currentUserId);    //获取当前用户TrueName,为增加流转信息提供数据
            WorkFlowItem  wfi  = bdb.WorkFlowItems.Where(i => i.WfInstanceId == instanceId).FirstOrDefault();   //获取当前流程信息
            ItServiceItem cisi = bdb.ItServiceItems.Where(i => i.ID == isi.ID).FirstOrDefault();                //获取当前业务数据的信息

            //业务数据更新开始
            cisi.Title          = isi.Title;
            cisi.applicant      = isi.applicant;
            cisi.applicant_dept = isi.applicant_dept;
            //cisi.description = isi.description;
            cisi.isitype     = isi.isitype;
            cisi.sub_isitype = isi.sub_isitype;
            cisi.end_isitype = isi.end_isitype;
            cisi.Object      = isi.Object;
            cisi.Topic       = isi.Topic;
            cisi.Purpose     = isi.Purpose;
            cisi.Status      = 1;
            if (NextLink == "驳回")
            {
                cisi.Status = 3;
            }
            if (isComplete == 1)
            {
                cisi.isiCompleteDate = DateTime.Now;
                if (NextLink == "撤销")
                {
                    cisi.Status = 4;
                }
                else
                {
                    cisi.Status = 2;
                }
            }

            #region 审批意见更新开始
            if (Opinion != null)
            {
                if (Convert.ToString(Opinion) != "")
                {
                    if (wfi.WfWriteField.Trim() == "FirstExamine")
                    {
                        cisi.FirstExamine = cisi.FirstExamine + "<br>" + Opinion + "     (意见填写人:" + user.TrueName + "    时间:" + DateTime.Now + ")";
                    }
                    if (wfi.WfWriteField.Trim() == "SecondExamine")
                    {
                        cisi.SecondExamine = cisi.SecondExamine + "<br>" + Opinion + "     (意见填写人:" + user.TrueName + "    时间:" + DateTime.Now + ")";
                    }
                    if (wfi.WfWriteField.Trim() == "LastExamine")
                    {
                        cisi.LastExamine = cisi.LastExamine + "<br>" + Opinion + "     (意见填写人:" + user.TrueName + "    时间:" + DateTime.Now + ")";
                    }
                }
            }
            #endregion


            if (wfi != null)
            {
                wfi.WfCurrentUser = CurrentUser;
                wfi.Wfstatus      = CurrentState;
                wfi.WfWriteField  = OpinionField;
                if (isComplete == 1)
                {
                    wfi.WfCompleteDate = DateTime.Now;
                }
                wfi.WfFlowChart = wfi.WfFlowChart + "->" + trackerInstance.CurrentState + "(" + user.TrueName + ")" + completeStr;          //增加流转信息
                try
                {
                    bdb.SaveChanges();
                    var json = new
                    {
                        okMsg = "提交成功"
                    };

                    return(Json(json, "text/html", JsonRequestBehavior.AllowGet));
                }
                catch (Exception e)
                {
                    var json = new
                    {
                        errorMsg = "提交失败"
                    };

                    return(Json(json, "text/html", JsonRequestBehavior.AllowGet));
                }
            }
            else
            {
                var json = new
                {
                    errorMsg = "流程不存在"
                };

                return(Json(json, "text/html", JsonRequestBehavior.AllowGet));
            }
        }
Пример #8
0
        public ActionResult DrafterToNextState(ItServiceItem isi, Guid instanceId, string NextLink, string libid)  //起草者到下一环节
        {
            string[] strs = NextLink.Trim().Split('(');

            AutoResetEvent syncEvent = new AutoResetEvent(false);

            WorkflowApplication wfApp = new WorkflowApplication(new ItService())
            {
                InstanceStore   = CreateInstanceStore(),
                PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e)
                {
                    //var ex = e.GetInstanceExtensions<CustomTrackingParticipant>();
                    // Outputs = ex.First().Outputs.ToString();`
                    return(PersistableIdleAction.Unload);
                },
                Completed = delegate(WorkflowApplicationCompletedEventArgs e)
                {
                },
                Aborted = delegate(WorkflowApplicationAbortedEventArgs e)
                {
                },
                Unloaded = delegate(WorkflowApplicationEventArgs e)
                {
                    syncEvent.Set();
                },
                OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
                {
                    return(UnhandledExceptionAction.Terminate);
                },
                Idle = delegate(WorkflowApplicationIdleEventArgs e)
                {
                }
            };
            var StateTracker = new StateMachineStateTracker(wfApp.WorkflowDefinition); //当前状态追踪

            wfApp.Extensions.Add(StateTracker);
            wfApp.Extensions.Add(new StateTrackerPersistenceProvider(StateTracker));
            var cu = new CustomTrackingParticipant();         //获取Activity内部变量

            wfApp.Extensions.Add(cu);                         //获取Activity内部变量需要的追踪器
            //Guid instanceId = wfApp.Id;
            var trackerInstance = StateMachineStateTracker.LoadInstance(instanceId, wfApp.WorkflowDefinition, ConfigurationManager.ConnectionStrings["ApacheConnection"].ConnectionString);

            wfApp.Load(instanceId);
            //BookmarkResumptionResult result = wfApp.ResumeBookmark(trackerInstance.CurrentState, NextLink.Trim());
            BookmarkResumptionResult result = wfApp.ResumeBookmark(trackerInstance.CurrentState, strs[0]);

            syncEvent.WaitOne();
            //string CurrentUser = cu.Outputs["CurrentUser"].ToString();
            string CurrentUser = db.LibraryApprovers.ToList().First(p => (p.LibID == libid) && (p.ApproverName == strs[1].Replace(")", ""))).Approver;
            //string CurrentRole = cu.Outputs["CurrentRole"].ToString();
            string OpinionField = cu.Outputs["OpinionField"].ToString();
            string Drafter      = cu.Outputs["Drafter"].ToString();
            var    CurrentState = StateTracker.CurrentState;
            //var Pt = StateTracker.PossibleTransitions;
            ApplicationUser user = db.Users.Include(i => i.Roles).FirstOrDefault(i => i.UserName == Drafter);    //获取当前用户username

            isi.drafter       = Drafter;
            isi.isiCreateDate = DateTime.Now;
            isi.Status        = 1;
            bdb.ItServiceItems.Add(isi);      //添加业务数据
            try
            {
                bdb.SaveChanges();
            }
            catch
            {
                var json = new
                {
                    errorMsg = "添加业务数据出错"
                };

                return(Json(json, "text/html", JsonRequestBehavior.AllowGet));
            }
            WorkFlowItem wf = new WorkFlowItem();

            wf.WfInstanceId   = instanceId;
            wf.WfType         = "专病库IT服务申请";
            wf.WfCurrentUser  = CurrentUser;
            wf.WfDrafter      = Drafter;
            wf.WfWriteField   = OpinionField;
            wf.Wfstatus       = CurrentState;
            wf.WfBussinessUrl = "/ItService/OpenWorkFlow?id=" + instanceId;
            wf.WfCreateDate   = DateTime.Now;
            wf.WfBusinessId   = isi.ID; //添加业务数据关联
            wf.WfFlowChart    = trackerInstance.CurrentState + "(" + user.TrueName + ")";
            bdb.WorkFlowItems.Add(wf);
            bdb.SaveChanges();
            try
            {
                bdb.SaveChanges();
                var json = new
                {
                    okMsg = "流程保存成功"
                };

                return(Json(json, "text/html", JsonRequestBehavior.AllowGet));
            }
            catch
            {
                var json = new
                {
                    errorMsg = "流程保存出错"
                };

                return(Json(json, "text/html", JsonRequestBehavior.AllowGet));
            }
        }
        public void TrackerShouldReportPreviousState()
        {
            var activity = new StateMachineExample();
            var host = WorkflowApplicationTest.Create(activity);
            var tracker = new StateMachineStateTracker(activity);
            Debug.Assert(host != null, "host != null");
            Debug.Assert(host.Extensions != null, "host.Extensions != null");
            host.Extensions.Add(tracker);

            try
            {
                // Using Microsoft.Activities.Extensions run the workflow until a bookmark named "T1"
                Assert.IsInstanceOfType(
                    host.TestWorkflowApplication.RunEpisode("T1", Constants.Timeout), typeof(WorkflowIdleEpisodeResult));

                WorkflowTrace.Information("First Idle");
                tracker.Trace();

                Debug.Assert(tracker.TrackedStateMachines != null, "tracker.TrackedStateMachines != null");
                Assert.AreEqual(1, tracker.TrackedStateMachines.Count);
                var stateTrackerInfo = tracker.TrackedStateMachines.Values.ElementAt(0);
                Debug.Assert(stateTrackerInfo != null, "stateTrackerInfo != null");
                Assert.AreEqual(null, stateTrackerInfo.PreviousState);
                Assert.AreEqual(null, tracker.PreviousState);
                Assert.AreEqual(tracker.PreviousState, stateTrackerInfo.PreviousState);
                Debug.Assert(stateTrackerInfo.Transitions != null, "stateTrackerInfo.Transitions != null");
                Assert.AreEqual(2, stateTrackerInfo.Transitions.Count);
                Assert.AreEqual("T1, T2", stateTrackerInfo.PossibleTransitions);

                // Run until bookmark "T3"
                Assert.IsInstanceOfType(
                    host.TestWorkflowApplication.ResumeEpisodeBookmark("T1", null, "T3"),
                    typeof(WorkflowIdleEpisodeResult));

                WorkflowTrace.Information("Second Idle");
                tracker.Trace();

                // Use the tracker operations that are forwarded to the current state
                Debug.Assert(tracker.TrackedStateMachines != null, "tracker.TrackedStateMachines != null");
                Assert.AreEqual(1, tracker.TrackedStateMachines.Count);
                Assert.AreEqual("State1", tracker.PreviousState);
                Debug.Assert(tracker.Transitions != null, "tracker.Transitions != null");
                Assert.AreEqual(2, tracker.Transitions.Count);
                Assert.AreEqual("T3, T5", tracker.PossibleTransitions);

                // Resume bookmark T5 and run until complete
                Assert.IsInstanceOfType(
                    host.TestWorkflowApplication.ResumeEpisodeBookmark("T5", null),
                    typeof(WorkflowCompletedEpisodeResult));

                Assert.AreEqual(1, tracker.TrackedStateMachines.Count);
            }
            finally
            {
                tracker.Trace();
                Debug.Assert(host.Tracking != null, "host.Tracking != null");
                host.Tracking.Trace();
            }
        }
        public void TrackerShouldConvertToAndFromXml()
        {
            var activity = new StateMachineExample();
            var host = WorkflowApplicationTest.Create(activity);
            var tracker1 = new StateMachineStateTracker(activity);
            Debug.Assert(host != null, "host != null");
            Debug.Assert(host.Extensions != null, "host.Extensions != null");
            host.Extensions.Add(tracker1);

            try
            {
                host.TestWorkflowApplication.RunEpisode("T1", Constants.Timeout);
                host.TestWorkflowApplication.ResumeEpisodeBookmark("T1", null, "T3");

                var xml = tracker1.ToXml();

                WorkflowTrace.Information("*** Tracker1***");
                WorkflowTrace.Information(xml);
                WorkflowTrace.Information(Environment.NewLine);

                var tracker2 = StateMachineStateTracker.Parse(activity, xml);
                WorkflowTrace.Information("*** Tracker2***");
                WorkflowTrace.Information(tracker2.ToXml());
                WorkflowTrace.Information(Environment.NewLine);

                Assert.AreEqual(tracker1.CurrentState, tracker2.CurrentState);
                Assert.AreEqual(tracker1.CurrentStateMachine, tracker2.CurrentStateMachine);
                Assert.AreEqual(tracker1.InstanceId, tracker2.InstanceId);
                Assert.AreEqual(tracker1.PossibleTransitions, tracker2.PossibleTransitions);
                Assert.AreEqual(tracker1.PreviousState, tracker2.PreviousState);
                Assert.AreEqual(tracker1.PreviousStateMachine, tracker2.PreviousStateMachine);
                Assert.AreEqual(tracker1.RootActivity, tracker2.RootActivity);
                AssertHelper.AreEqual(tracker1.StateHistory, tracker2.StateHistory);
                AssertHelper.AreEqual(tracker1.Transitions, tracker2.Transitions);
            }
            finally
            {
                host.Tracking.Trace();
            }
        }
        public void TrackedStateMachinesShouldBeEmptyOnCreate()
        {
            // Arrange
            var tracker = new StateMachineStateTracker(new StateMachine());

            // Act
            var trackedMachines = tracker.TrackedStateMachines;

            // Assert
            Assert.IsNotNull(trackedMachines);
        }
        public void PossibleTransitionsWithNoCurrentShouldReturnNull()
        {
            // Arrange
            var tracker = new StateMachineStateTracker(new Sequence());

            // Act / Assert
            Assert.IsNull(tracker.PossibleTransitions);
        }
        public void HistoryIsCircularBuffer()
        {
            // Arrange
            const int MaxHistory = 3;
            var activity = new StateMachineExample();
            var host = WorkflowApplicationTest.Create(activity);
            var tracker = new StateMachineStateTracker(activity, MaxHistory);
            host.Extensions.Add(tracker);

            try
            {
                // Start the workflow - run to State1 with bookmark "T1"
                host.TestWorkflowApplication.RunEpisode("T1", Constants.Timeout);

                // History
                // State1
                CollectionAssert.AreEqual(tracker.StateHistory.ToList(), new[] { "State1" });

                // Run until State2 with bookmark "T3"
                host.TestWorkflowApplication.ResumeEpisodeBookmark("T1", null, "T3");

                // History
                // State1
                // State2
                CollectionAssert.AreEqual(tracker.StateHistory.ToList(), new[] { "State1", "State2" });

                // Run until State1 with bookmark "T1"
                host.TestWorkflowApplication.ResumeEpisodeBookmark("T3", null, "T1");

                // History
                // State1
                // State2
                // State1
                CollectionAssert.AreEqual(tracker.StateHistory.ToList(), new[] { "State1", "State2", "State1" });

                // Run until State2 with bookmark "T3"
                host.TestWorkflowApplication.ResumeEpisodeBookmark("T1", null, "T3");

                // History
                // State1 <- Dropped from buffer
                // State2
                // State1
                // State2
                Assert.AreEqual(MaxHistory, tracker.StateHistory.Count());
                CollectionAssert.AreEqual(tracker.StateHistory.ToList(), new[] { "State2", "State1", "State2" });
            }
            finally
            {
                tracker.Trace();
                Debug.Assert(host.Tracking != null, "host.Tracking != null");
                host.Tracking.Trace();
            }
        }
        public void CurrentStateWithNoCurrentShouldReturnNull()
        {
            // Arrange
            var tracker = new StateMachineStateTracker(new Sequence());

            // Act / Assert
            Assert.IsNull(tracker.CurrentState);
        }