C# .NET 6 使用WorkFlow Core 创建工作审批流

1,背景

  工作流思想在上世纪60年代就有人提出过;70年代就有人开始尝试,但是由于当时许多的限制,工作流一直没有成功的被实现;80年代才出现第一批成功的工作流系统;90年代工作流技术走向了第一个发展高峰期;90年代后至今工作流出现了很多版本,但是主旨还是不变的,为了使我们的工作变得更加高效。

  通俗点,我们经常使用的OA系统上。关于一个材料的申报,又或者个人的请假。这些流程就属于工作流(工作审批流)。其中对于审批人和各个节点是可以动态操作的。

  工作流可以通过数据库设计的形式实现,也可以使用第三方的框架Elsa,Workflow Core。本文使用第二种,并详细的介绍一下代码实现和json实现工作流程。

2,安装

  使用Nuget包管理工具安装以下的包:  

    Workflow Core 3.10.0          核心包不解释

    WorkflowCore.DSL 3.10.0        json或者yaml注入需要

    WorkflowCore.Persistence.MySQL    持久化

3,文档

  JSON / YAML Definitions - Workflow Core (workflow-core.readthedocs.io)

 

  WorkFlowCore 加载Json文件 - 编程代码 (cscoder.cn)

 

4,例子

1,创建项目

  控制台或者WebApi项目均可,这里拿WebApi项目举例。(版本用的是.net 6)

2,添加工步

  工步文件需要继承StepBody。现在添加一个Hello.cs和Goodbye的工步,代码如下:

using WorkflowCore.Interface; using WorkflowCore.Models;  namespace WorkFlowCore_Test.WorkFlows.HelloWord.Steps {     public class Hello : StepBody     {         public override ExecutionResult Run(IStepExecutionContext context)         {             Console.WriteLine("Hello World!");             return ExecutionResult.Next();         }     } }

 

using WorkflowCore.Interface; using WorkflowCore.Models;  namespace WorkFlowCore_Test.WorkFlows.HelloWord.Steps {     public class Goodbye : StepBody     {         public override ExecutionResult Run(IStepExecutionContext context)         {             Console.WriteLine("Goodbye World!");             return ExecutionResult.Next();         }     } }

3,添加工作流文件

  工作流文件需要继承IWorkflow。现在开始添加:

using WorkflowCore.Interface; using WorkFlowCore_Test.WorkFlows.HelloWord.Steps;  namespace WorkFlowCore_Test.WorkFlows.HelloWord {     public class HelloWorldWorkflow : IWorkflow     {         public string Id => "HelloWorld";          public int Version => 1;          public void Build(IWorkflowBuilder<object> builder)         {             builder                 .StartWith<Hello>()                 .Then<Goodbye>();         }     } }

4,配置和启动

  基本数据都准备好了之后,在项目启动文件进行一下配置。代码如下:

using Microsoft.AspNetCore.Mvc; using System.Xml.Linq; using WorkflowCore.Interface; using WorkflowCore.Services; using WorkflowCore.Services.DefinitionStorage; using WorkFlowCore_Test.Utils; using WorkFlowCore_Test.WorkFlows.AskForLeave.Model; using WorkFlowCore_Test.WorkFlows.AskForLeave; using WorkFlowCore_Test.WorkFlows.HelloWord; using WorkFlowCore_Test.WorkFlows.IfStatement; using WorkFlowCore_Test.WorkFlows.IfStatement.Model; using WorkFlowCore_Test.WorkFlows.Json.Steps; using WorkFlowCore_Test.WorkFlows.SimpleDecision;  namespace WorkFlowCore_Test {     public class Program     {         public static void Main(string[] args)         {             var builder = WebApplication.CreateBuilder(args);             // Add services to the container.             builder.Services.AddAuthorization();             builder.Services.AddControllers();             builder.Services.AddLogging(); // WorkflowCore需要用到logging service             //持久化             builder.Services.AddWorkflow(cfg =>             {                 cfg.UseMySQL("server=127.0.0.1;Database=Workflow;Uid=root;Pwd=xunpai123.", true, true);             });             builder.Services.AddWorkflowDSL();//用来注入json和yaml              var app = builder.Build();              //核心注入方法             UseWorkflow(app);              app.UseAuthorization();             app.MapControllers();             app.Run();         }           public static void UseWorkflow(WebApplication app)         {             var host = app.Services.GetService<IWorkflowHost>();              #region 工步注册             //c#代码注册             host?.RegisterWorkflow<HelloWorldWorkflow>();             //json注册             #endregion              host?.Start();             // 通过DI获取IHostApplicationLifetime实例             var applicationLifetime = app.Services.GetService(typeof(IHostApplicationLifetime)) as IHostApplicationLifetime;             applicationLifetime?.ApplicationStopping.Register(() =>             {                 host?.Stop();             });         }       } }

 

  这个时候我们添加api控制器进行调用这个helloworld的流程。代码如下:

using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Diagnostics; using System.Net.Http.Json; using System.Text.Json.Nodes; using WorkflowCore.Interface; using WorkflowCore.Models; using WorkflowCore.Services; using WorkflowCore.Services.DefinitionStorage; using WorkFlowCore_Test.Utils; using WorkFlowCore_Test.WorkFlows.AskForLeave.Model; using WorkFlowCore_Test.WorkFlows.SimpleDecision;  namespace WorkFlowCore_Test.Controllers {     [Route("api/[controller]")]     [ApiController]     public class TestApiController : ControllerBase     {         private IWorkflowController WorkflowService;         private IWorkflowHost WorkflowHost;         public TestApiController(IWorkflowController workflowService, IWorkflowHost workflowHost)         {             WorkflowService = workflowService;             WorkflowHost = workflowHost;         }          [Route("WorkFlowCoreTestDemo")]         [HttpGet]         public string WorkFlowCoreTestDemo()         {             //var initialData = new LeaveRequestData             //{             //    RequestId = "11111",             //    RequestMsg = "开始请假"             //};              //WorkflowHost.StartWorkflow("LeaveRequestWorkflow", 1, initialData);              WorkflowService.StartWorkflow("HelloWorld");             return "true";         }                } }

5,效果展示

  启动后调用我们的控制器方法,然后观看console 的变化,如图:

C# .NET 6 使用WorkFlow Core 创建工作审批流

C# .NET 6 使用WorkFlow Core 创建工作审批流

 

6,请假单流程

  请假单的流程创建的话需要用到等待的函数,等待管理员进行审核后进行下一步的操作。请假单的流程代码如下:

    public class LeaveRequestData     {         public string RequestId { get; set; }         public bool ManagerApproved { get; set; }         public bool HRApproved { get; set; }         public string RequestMsg { get; set; }     }

using WorkflowCore.Interface; using WorkFlowCore_Test.WorkFlows.AskForLeave.Model; using WorkFlowCore_Test.WorkFlows.AskForLeave.Steps; using WorkFlowCore_Test.WorkFlows.SimpleDecision.Steps;  namespace WorkFlowCore_Test.WorkFlows.AskForLeave {     public class AskForLeaveWorkflow : IWorkflow<LeaveRequestData>     {         public string Id => "LeaveRequestWorkflow";         public int Version => 1;          public void Build(IWorkflowBuilder<LeaveRequestData> builder)         {             builder.StartWith(context => Console.WriteLine("提交请假申请"))                 .Activity("manage-audit", (data) => data.RequestMsg)                     .Output(data => data.ManagerApproved, step => step.Result)                 .Then<ManagerApprovalStep>().Input(step => step.AuditDataInfo, data => data)                 .If(data => data.ManagerApproved)                     .Do(then => then.StartWith(context => Console.WriteLine("经理审核")));                       }     } }

  然后创建好之后,在启动文件进行注册一下:

            host?.RegisterWorkflow<AskForLeaveWorkflow, LeaveRequestData>();

  好了,接下来我们就可以用接口的形式进行模拟了。首先我们新增一个接口用来模拟申请请求代码如下:

        [Route("WorkFlowCoreTestDemo")]         [HttpGet]         public string WorkFlowCoreTestDemo()         {             var initialData = new LeaveRequestData             {                 RequestId = "11111",                 RequestMsg = "开始请假"             };              WorkflowHost.StartWorkflow("LeaveRequestWorkflow", 1, initialData);              //WorkflowService.StartWorkflow("HelloWorld");             return "true";         }

  然后创建一个管理员的审批方法,用来审核通过或者拒绝。代码如下:

        [Route("WorkFlowCoreTestDemo4")]         [HttpGet]         public async Task<string> WorkFlowCoreTestDemo4()         {             //获取待决活动             var approval = await WorkflowHost.GetPendingActivity("manage-audit", "worker1");                          if (approval != null)             {                 Console.WriteLine("需要批准的" + approval.Parameters);                 //提交活动成功                 await WorkflowHost.SubmitActivitySuccess(approval.Token, true);//true,代表审批通过。逻辑验证在步骤里面             }             return "请假工作流";         }

  好了,这样就形成闭环了。大家可以在postman上请求测试一下,观察console的变化了。

7,json注入

  最后就是json注入的方式了,这种方式也是目前我比较倾向的方式,和前端对接就很方便的。前端按照固定的格式给后端传入json数据,后端根据json数据解析工步进行开启工作流。

  首先需要创建一个json文件,json文件代码如下:

{   "Id": "HelloWorldJson",   "Version": 1,   "Steps": [     {       "Id": "Hello",       "StepType": "",       "NextStepId": "Bye"     },     {       "Id": "Bye",       "StepType": ""      }   ] }

  然后在启动文件配置,注入一下json工作流:

//json注册 var loader = app.Services.GetService<IDefinitionLoader>();      var json = System.IO.File.ReadAllText("WorkFlows/Json/JsonYaml.json");// 假设文件位于程序运行目录 // 【json注入时候,stepType写这个程序集的类名】获取并打印全限定名,包括程序集名称 //Type myClassType = typeof(HelloWorldStep); //string fullAssemblyClassName = myClassType.AssemblyQualifiedName; loader?.LoadDefinition(json, Deserializers.Json);

  到这里就可以了,创建一个api方法来调用看看:

        [Route("WorkFlowCoreTestDemo6")]         [HttpGet]         public string WorkFlowCoreTestDemo6()         {             WorkflowHost.StartWorkflow("HelloWorldJson", 1, null);             return "";         }

  到这里就可以实现json注入工作流了。不过细心的朋友就发现了,我给的json文件中的step的type为什么是空的呢?是因为StepType取的是项目程序集工步的类名称,因为我的电脑项目和你们的项目不一样,所以这里没有写。大家可以自行百度搜搜看,我这里还是放一下我的json例子吧。

{   "Id": "HelloWorldJson",   "Version": 1,   "Steps": [     {       "Id": "Hello",       "StepType": "WorkFlowCore_Test.WorkFlows.Json.Steps.HelloWorldStep, WorkFlowCore-Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",       "NextStepId": "Bye"     },     {       "Id": "Bye",       "StepType": "WorkFlowCore_Test.WorkFlows.Json.Steps.HelloWorldStep, WorkFlowCore-Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"      }   ] }

 

5,结语

  例子备注写的比较多,就不多赘述了。有问题的话就留言吧,感谢观看~

发表评论

相关文章