背景:
刚进某地产公司,就是做一个工作流的小Demo,就是画一条采购的工作流,然后代码实现它。
刚开始的时候真的其实挺迷茫的,然后就从自己比较熟悉的实体做起,接着是controller,然后是view,代码都是参考过N份的,最后代码写的差不多了,然后才开始画一条流程。流程图就画了前后有6份,然后改来改去,还好有各位哥哥帮忙,。最后一条流程总算是走了下来。就在上周五的时候,SA突然让我就开始熟悉需求了,没想到这么快就要开始干活了。
简谈
最开始做工作流的时候,感觉它跟职责链模式很像,它的处理都是一级一级的,尤其是用工作流处理一个大企业的工作流程的时候,必须要定义的非常严格,每一步都要在计划之内,人只是这一步流程上的资源而已。
做考核项目的时候,是用流程模板设计器做的图,但是考核项目快要做的时候,看到了一个Training Video,,发现居然也能用编程方式编出整个流程。
虽然编程方式不像可视环境那么舒服,但是学习这种方式操作工作流对于以后我们在编程中控制工作流是很有好处的。
源码展示
class Program { static void Main(string[] args) { #region 编程创建流程——lhc——2015年1月7日14:52:07 ////创建一个流程 //WfProcessDescriptor process = new WfProcessDescriptor("workFlowTest"); //process.Name = "工作流测试";//流程命名 ////创建一个首节点 //WfActivityDescriptor initActDesp = new WfActivityDescriptor("N0", WfActivityType.InitialActivity); //initActDesp.Name = "这是一个首节点"; ////创建一个结束点 //WfActivityDescriptor completeActDesp = new WfActivityDescriptor("N1", WfActivityType.CompletedActivity); //completeActDesp.Name = "结束点"; //process.Activities.Add(initActDesp); //将首节点加入流程中 //process.Activities.Add(completeActDesp);//将尾节点加入流程中 // //创建一个正常点 //WfActivityDescriptor normalActDesp = new WfActivityDescriptor("N2", WfActivityType.NormalActivity); //normalActDesp.Name = "这是一个比较正常点"; ////从授权中心拿人 //var users = OguMechanismFactory.GetMechanism().GetObjects<IUser>(SearchOUIDType.LogOnName, "fanhy"); ////加入资源到正常点中 //normalActDesp.Resources.Add(new WfUserResourceDescriptor(users[0])); //加入资源 //process.Activities.Add(normalActDesp);//加入到流程集合中 ////流程之间的连线 ////initActDesp.ToTransitions.AddForwardTransition(completeActDesp); //从起始点加一根向前的线到终结点 ////completeActDesp.ToTransitions.AddBackwardTransition(initActDesp);//从终结点加一个到起始点的回去的线 //initActDesp.ToTransitions.AddForwardTransition(normalActDesp); //从起点到正常点的连线 //normalActDesp.ToTransitions.AddForwardTransition(completeActDesp);//从正常点到终结点的连线 ////保存流程:从内存到DB //WfProcessDescriptorManager.SaveDescriptor(process); #endregion #region 读取工作流信息——lhc——2015年1月7日15:33:15 ////根据名称读取工作流 // IWfProcessDescriptor processDesp = WfProcessDescriptorManager.GetDescriptor("workFlowTest"); // // Console.WriteLine(processDesp.Name);//输出工作流名称 // EnumActivities(processDesp.InitialActivity); //打印起点 #endregion #region 启动流程——lhc——2015年1月7日16:25:40 //////根据名称读取工作流 //IWfProcessDescriptor processDesp = WfProcessDescriptorManager.GetDescriptor("workFlowTest"); //WfProcessStartupParams startupParams = new WfProcessStartupParams(); //启动流程的参数 //startupParams.ProcessDescriptor = processDesp; //要启动的流程赋值 ////运行态可以重新定义人(资源),流程设计器里提前配好的资源只是一个默认值 //startupParams.Assignees.Add(processDesp.InitialActivity.Resources.ToUsers()); //将第一个节点的人抄过来 //startupParams.ResourceID = UuidHelper.NewUuidString();//UUID赋值 //IWfProcess process = WfRuntime.StartWorkflow(startupParams);//启动流程 ////打印 //Console.WriteLine(process.ID);//流程ID //Console.WriteLine(process.Descriptor.Name);//流程描述 ////////--------在这之前,所有的操作都是在内存中的 //WfRuntime.PersistWorkflows();//持久化工作流 //Console.WriteLine(process.ID);//ID #endregion #region 获取运行时流程——lhc——2015年1月7日16:25:49 ////288926d4-8c53-bdb5-47b1-b655d002b1e7 //IWfProcess processStart = WfRuntime.GetProcessByProcessID("288926d4-8c53-bdb5-47b1-b655d002b1e7"); ////Console.WriteLine(); //Console.WriteLine(processStart.CurrentActivity.Descriptor.Name);//获取当前节点名称 //TODO:没有找到UserTaskAdapter // UserTaskCollection tasks = UserTaskAdapter.Instance.LoadUserTasks(builder => builder.AppendItem("Activity_id",processStart .CurrentActivity .ID)); // //Console.WriteLine(task.count);//输出数量 #endregion #region 流程的流转——lhc——2015年1月7日16:25:59 // IWfProcess processStart = WfRuntime.GetProcessByProcessID("288926d4-8c53-bdb5-47b1-b655d002b1e7"); // //找到起始点的下一个结点 // IWfActivityDescriptor targetActDesp = processStart.InitialActivity.Descriptor.ToTransitions[0].ToActivity; // //流转参数 // WfTransferParams transferParams = new WfTransferParams(targetActDesp); // transferParams.Assignees.Add(targetActDesp.Resources.ToUsers()); //加入资源 // processStart.MoveTo(transferParams); //从第一个节点流转到下一个 // //流程上下文 ////WfRuntime.ProcessContext // //处理挂起的流程——一个流程只能有一个处于挂起的 // //WfRuntime.ProcessPendingActivity(); // //等待一个外部条件 // // // processStart.ApplicationRumtimeParameters["Data"] = "lhc";//流程参数赋值,但是WfRuntime.PersistWorkflows(); 不能被此条语句保存 // //强制保存的语句——important // //一般经过方法调用流程的都不用这句话。 // WfRuntime.ProcessContext.AffectedProcesses.AddOrReplace(processStart );//请执行保存 // //将内存中的操作持久化到数据库 // WfRuntime.PersistWorkflows(); //moveto这种大改动可以被此条语句保存 // Console.WriteLine(processStart.CurrentActivity.Descriptor.Name); //打印出当前节点名称 #endregion #region executor启动流程——lhc——2015年1月7日21:49:53 //流程启动参数 WfProcessStartupParams startupParams = new WfProcessStartupParams(); //获取要启动流程 startupParams.ProcessDescriptor = WfProcessDescriptorManager.GetDescriptor("workFlowTest"); startupParams .ResourceID =UuidHelper .NewUuidString ();//流程GUID赋值 //加入资源 startupParams.Assignees.Add(startupParams.ProcessDescriptor.InitialActivity.Resources.ToUsers()); WfStartWorkflowExecutor executor = new WfStartWorkflowExecutor(null, startupParams);//使用executor启动流程 //改变标题——加入委托方法 executor.PrepareMoveToTasks += new PrepareTasksEventHandler(executor_PrepareMoveToTasks); IWfProcess process= executor.Execute();//执行 Console.WriteLine(process .ID);//输出流程ID #endregion } #region executor启动流程上搭载的方法——lhc——2015年1月7日21:50:11 private static void executor_PrepareMoveToTasks(WfExecutorDataContext dataContext, MCS.Library.SOA.DataObjects.UserTaskCollection tasks) { tasks.ForEach(t => t.TaskTitle = "lhc"); } #endregion #region 根据节点深度遍历流程 //foreach打印流程名称 //private static void EnumActivities(IWfActivityDescriptor astDesp) //{ // Console.WriteLine(astDesp.Name); //打印节点名称 // astDesp.Resources.ToUsers().ForEach(u => Console.WriteLine(u.DisplayName)); //foreach打印节点资源名称 // if (astDesp.ActivityType !=WfActivityType .CompletedActivity) // { // //每个节点都有两端,fromActivity和toActivity; // //深度遍历搜索 // astDesp.ToTransitions.ForEach(t => EnumActivities(t.ToActivity)); // } //} #endregion }
PS: 为了使用操作工作流的各种对象,还要引入一些平台封装的类库什么的
小结
感觉在程序中,所有的东西都是为一整条流程服务的,就连人也变成了资源依附在流程上,就像这里所提倡的,人依附于事的思想。