• 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()
                    .Then();
            }
        }
    }
    复制代码

    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();
    
                #region 工步注册
                //c#代码注册
                host?.RegisterWorkflow();
                //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 的变化,如图:

     

    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
        {
            public string Id => "LeaveRequestWorkflow";
            public int Version => 1;
    
            public void Build(IWorkflowBuilder builder)
            {
                builder.StartWith(context => Console.WriteLine("提交请假申请"))
                    .Activity("manage-audit", (data) => data.RequestMsg)
                        .Output(data => data.ManagerApproved, step => step.Result)
                    .Then().Input(step => step.AuditDataInfo, data => data)
                    .If(data => data.ManagerApproved)
                        .Do(then => then.StartWith(context => Console.WriteLine("经理审核")));
    
                
            }
        }
    }
    复制代码

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

                host?.RegisterWorkflow();

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

    复制代码
            [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();     
    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,结语

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

  • 相关阅读:
    解决 Can‘t connect to MySQL server on ‘x‘ (10048) 问题
    Hudi(三)集成Flink
    鸿蒙DevEco Studio 4.1 Release-模拟器启动方式错误
    报表如何动态切换数据源
    python 根据shp文件解析经纬度市县信息
    Java扫码点餐小程序源码 智慧点餐系统源码 点餐APP SaaS模式
    Vue--Axios详解
    第 46 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海),签到题6题
    SQLite 3.43.0 发布,又有啥新功能?
    外包干了三年,真废了。。。
  • 原文地址:https://www.cnblogs.com/BFMC/p/18233359