65.9K
CodeProject 正在变化。 阅读更多。
Home

使用状态机工作流 4.0 和 SQL Server 持久性的申购流程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (3投票s)

2013 年 9 月 6 日

CPOL

3分钟阅读

viewsIcon

32879

downloadIcon

1396

使用状态机工作流 4.0 和 SQL Server 持久性的申购流程。

引言  

这是一个使用 Visual Studio 2010 开发的示例工作流应用程序,它使用状态机和 SQL Server 持久性。.NET 3.5 中的状态机与 4.0 不同,SQL Server 数据库模式和表已从以前的版本更改。状态机工作流基于状态、转换和最终状态。可以有多个最终状态,并且随着流程的继续,状态转换发生。另一个原因是工作流方向可以基于人为决策而改变。

背景

为了创建应用程序,您必须在系统中安装以下工具/包。

您必须具备以下项目

  • Microsoft Visual Studio 2010 Service Pack 1
  • Microsoft .NET Framework 4 Platform Update 1 - Runtime Update (KB2478063)
  • Microsoft .NET Framework 4 Platform Update 1 – Visual Studio 2010 SP1 的设计时更新 (KB2495593)
  • 具有持久性数据库作为实例存储的 SQL Server 作为“PersistenceDataBase”

设置持久性数据库的过程

Microsoft 提供了数据库脚本来设置实例存储,这些脚本可以在以下路径中找到:C:\Windows\Microsoft.NET\Framework\v4.0.30319\SQL\en

申购流程

申购流程工作流步骤

  1. 用户提出申购
  2. 生成申购单号
  3. 用户可以批准或拒绝申购
  4. 如果用户批准,流程继续到申购发放
  5. 如果用户拒绝,申购流程终止
  6. 申购被批准后,用户可以部分发放或完全发放
  7. 如果发放是完全发放,则工作流完成
  8. 如果发放是部分发放,则流程持续直到完全发放

工作流的状态:

  • 新建
  • 批准或拒绝
  • 部分
  • 完全

这些是工作流中的书签。 我们已经讨论过,状态机工作流由用户决策驱动,并利用了这些书签。 书签控制工作流,并且在人为干预后再次恢复。 在此示例中,有两种情况:

活动

 

创建新的申购订单,例如“申购 5”

状态保存为 "NEW"

 

对于每个申购订单,都会创建一个新的工作流实例,此工作流实例将持久保存在数据库中。

工作流 GUID 保存在实例存储数据库中,显示书签并显示工作流状态的当前执行状态,在此查询输出中显示为“空闲”。

如果用户拒绝订单,则工作流将被终止。

如果用户批准订单,则工作流程继续

现在,批准工作流后,需要发放库存。 需要用户的第二次干预才能继续工作流程。 用户需要发放库存。 如果用户发放库存,则工作流程会继续,但是根据状态机流程图,如果发放是部分发放,则不会完成。 只有当用户发放全部库存时,工作才会完成

使用代码

代码详情

using System;
using System.Activities;
using System.Activities.DurableInstancing;
using System.Collections.Generic;
using System.Runtime.DurableInstancing;
using System.Threading;
using System.Xml.Linq;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Activities.Hosting;
using System.Activities.Tracking;
using System.IO;
namespace IndentingProcess
{
   public class IndentOrderHost : IIndentOrderHost
    {
         IDictionary<Guid, WorkflowApplication> instances;
        static SqlWorkflowInstanceStore sqlWorkflowInstanceStore = SetupSqlpersistenceStore();
        static InstanceStore instanceStore;
        static AutoResetEvent instanceUnloaded = new AutoResetEvent(false);
        
        static Guid id;
        public IndentOrderHost()
        {
            instances = new Dictionary<Guid, WorkflowApplication>();
        }
        
        public WorkflowApplication LoadInstance(Guid instanceId)
        {
            // if the instance is in memory, return it
            if (instances.ContainsKey(instanceId))
                return this.instances[instanceId];
            Activity wf = new Activity2();
            IDictionary<string, object> inputs = new Dictionary<string, object>();
            inputs.Add("OrderStatus","Approve");
            WorkflowApplication instance = new WorkflowApplication(wf, inputs);
            instance.InstanceStore = sqlWorkflowInstanceStore;
            instance.Completed += OnWorkflowCompleted;
            instance.Idle += OnIdle;
            instance.Load(instanceId);
            instances.Add(instanceId, instance);
            return instance;
        }

        public System.Activities.WorkflowApplication CreateAndRun(string OrderName)
        {
            IDictionary<string, object> inputs = new Dictionary<string, object>();
            inputs.Add("OrderStatus", "New");


            Activity wf = new Activity2();
            WorkflowApplication instance = new WorkflowApplication(wf, inputs);
            instance.InstanceStore = sqlWorkflowInstanceStore;
            instance.PersistableIdle += OnIdleAndPersistable;
            instance.Completed += OnWorkflowCompleted;
            instance.Idle += OnIdle;
            string strGUID = "";
            strGUID = instance.Id.ToString();
            SaveRecords(strGUID, OrderName);
            instance.Persist();
            this.instances.Add(instance.Id, instance);
            instance.Run();

            return instance;
        }
        public WorkflowApplication LoadInstance(Guid instanceId , string status)
        {
            // if the instance is in memory, return it
            if (instances.ContainsKey(instanceId))
                return instances[instanceId];
            IDictionary<string, object> inputs = new Dictionary<string, object>();
            inputs.Add("OrderStatus", "New");


            Activity wf = new Activity2();
            WorkflowApplication instance = new WorkflowApplication(wf);
            
            instance.InstanceStore = sqlWorkflowInstanceStore;
            instance.Completed += OnWorkflowCompleted;
            instance.Idle += OnIdle;
            instance.Load(instanceId);
            instances.Add(instanceId, instance);
            return instance;
        }


       
        public void OnIdle(WorkflowApplicationIdleEventArgs e)
        {
        }

        public PersistableIdleAction OnIdleAndPersistable(WorkflowApplicationIdleEventArgs e)
        {
            return PersistableIdleAction.Persist;
        }

        // executed when instance is persisted
        public void OnWorkflowCompleted(WorkflowApplicationCompletedEventArgs e)
        {
            
        }

        public bool CanApproveToInstance(Guid instanceId)
        {
            WorkflowApplication instance = this.LoadInstance(instanceId , "AproveorReject");

            // if there are no bookmarks, the process has finalized
            if (instance.GetBookmarks().Count == 0)
            {
                
                return false;
            }
            else // if there are bookmarks, check if one of them
            // correspond with the "logged" vendor
            {
                foreach (BookmarkInfo bookmarkInfo in instance.GetBookmarks())
                {
                    if (bookmarkInfo.BookmarkName.Equals("New"))
                    {
                        
                        return true;
                    }
                }
                return false;
            }
        }

        public void UpdateStatus(Guid instanceId, int OrderID, string Status)
        {
            WorkflowApplication instance = this.LoadInstance(instanceId, Status);
            string bookmarkName = "New";
            if (Status == "Full" )
            {
                 bookmarkName = "Approve";
                instance.ResumeBookmark(bookmarkName, Status);
            }
            else
            { instance.ResumeBookmark(bookmarkName, Status); }
            
            updaterecords(Status, OrderID);
            instance.Completed = (CompletedArgs) =>
            {
                if (CompletedArgs.CompletionState == ActivityInstanceState.Closed)
                {

                }
                else
                { instance.Persist(); }

            };
        }


        private static SqlWorkflowInstanceStore SetupSqlpersistenceStore()
        {
            try
            {
                SqlWorkflowInstanceStore sqlWFInstanceStore =
                 new SqlWorkflowInstanceStore("Data Source=Server;Initial " + 
                 "Catalog=PersistenceDatabase;uid=pocuser;password=pocuser;");
                InstanceHandle handle = sqlWFInstanceStore.CreateInstanceHandle();
                InstanceView view = sqlWFInstanceStore.Execute(handle, 
                        new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(5));
                handle.Free();
                sqlWFInstanceStore.DefaultInstanceOwner = view.InstanceOwner;
                return sqlWFInstanceStore;
            }
            catch (Exception ex)
            {
                string strex = ex.Message;
                return null;
            }
          
        }
        private void SaveRecords(string strGUID, string strOrderName  )
        {
            SqlConnection sqlCon = new SqlConnection("Data Source=Server;" + 
              "Initial Catalog=PersistenceDatabase;uid=pocuser;password=pocuser;Asynchronous Processing=True");
            SqlCommand sqlCmd = new SqlCommand();
            sqlCmd.CommandText = "INSERT INTO [ContosoHR].[dbo].[IndentOrder]" + 
              " ([ID],[OrderStatus],[OrderName]) VALUES ('" + strGUID + "', 'New','" + 
              strOrderName + "') ";
            sqlCmd.Connection = sqlCon;
            sqlCon.Open();
            int intResult = sqlCmd.ExecuteNonQuery();
            sqlCon.Close();
        }
        private void updaterecords(string status ,int strGUID )
        {
            SqlConnection sqlCon = new SqlConnection("Data Source=Server;Initial " + 
              "Catalog=PersistenceDatabase;uid=pocuser;password=pocuser;Asynchronous Processing=True");
            SqlCommand sqlCmd = new SqlCommand();
            sqlCmd.CommandText = "update  [ContosoHR].[dbo].[IndentOrder]  set [OrderStatus]  = '" + 
              status + "' where Orderid  = " + strGUID + " ";
            sqlCmd.Connection = sqlCon;
            sqlCon.Open();
            int intResult = sqlCmd.ExecuteNonQuery();
            sqlCon.Close();
        }
    }
}

结论 

使用状态机和工作流引擎,开发人员可以创建一个流程来规范活动。

© . All rights reserved.