當前位置: 妍妍網 > 碼農

.NET 使用 WorkFlow Core 建立工作審批流

2024-07-04碼農

前言

工作流思想在上世紀60年代就有人提出過;70年代就有人開始嘗試,但是由於當時許多的限制,工作流一直沒有成功的被實作;80年代才出現第一批成功的工作流系統;90年代工作流技術走向了第一個發展高峰期;90年代後至今工作流出現了很多版本,但是主旨還是不變的,為了使我們的工作變得更加高效。

通俗點,我們經常使用的OA系統上。關於一個材料的申報,又或者個人的請假。這些流程就屬於工作流(工作審批流)。其中對於審批人和各個節點是可以動態操作的。

工作流可以透過資料庫設計的形式實作,也可以使用第三方的框架Elsa,Workflow Core。本文使用第二種,並詳細的介紹一下程式碼實作和json實作工作流程。

安裝

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

Workflow Core 3.10.0 核心包不解釋

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

WorkflowCore.Persistence.MySQL 持久化

文件

JSON / YAML Definitions - Workflow Core

https://workflow-core.readthedocs.io/en/latest/json-yaml/

WorkFlowCore 載入Json檔 - 編程程式碼 (cscoder.cn)

https://www.cscoder.cn/docs/dotnet-core-projects-workflow-core/workflow-core-json.html

例子

1、建立計畫

控制台或者WebApi計畫均可,這裏拿WebApi計畫舉例。(版本用的是.net 6)

2、添加工步

工步檔需要繼承StepBody。現在添加一個Hello.cs和Goodbye的工步,程式碼如下:

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

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

3、添加工作流檔

工作流檔需要繼承IWorkflow。現在開始添加:

using WorkflowCore.Interface;
using WorkFlowCore_Test.WorkFlows.HelloWord.Steps;
namespaceWorkFlowCore_Test.WorkFlows.HelloWord
{
public classHelloWorldWorkflow : IWorkflow
{
publicstring Id => "HelloWorld";
publicint Version => 1;
publicvoidBuild(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;
namespaceWorkFlowCore_Test
{
public classProgram
{
publicstaticvoidMain(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."truetrue);
});
builder.Services.AddWorkflowDSL();//用來註入json和yaml
var app = builder.Build();
//核心註入方法
UseWorkflow(app);
app.UseAuthorization();
app.MapControllers();
app.Run();
}
publicstaticvoidUseWorkflow(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;
namespaceWorkFlowCore_Test.Controllers
{
[Route("api/[controller]")]
[ApiController]
public classTestApiController : ControllerBase
{
private IWorkflowController WorkflowService;
private IWorkflowHost WorkflowHost;
publicTestApiController(IWorkflowController workflowService, IWorkflowHost workflowHost)
{
WorkflowService = workflowService;
WorkflowHost = workflowHost;
}
[Route("WorkFlowCoreTestDemo")]
[HttpGet]
publicstringWorkFlowCoreTestDemo()
{
//var initialData = new LeaveRequestData
//{
// RequestId = "11111",
// RequestMsg = "開始請假"
//};
//WorkflowHost.StartWorkflow("LeaveRequestWorkflow", 1, initialData);
WorkflowService.StartWorkflow("HelloWorld");
return"true";
}
}
}


5、效果展示

啟動後呼叫我們的控制器方法,然後觀看console 的變化,如圖:

6、請假單流程

請假單的流程建立的話需要用到等待的函式,等待管理員進行稽核後進行下一步的操作。請假單的流程程式碼如下:

public classLeaveRequestData
{
publicstring RequestId { getset; }
publicbool ManagerApproved { getset; }
publicbool HRApproved { getset; }
publicstring RequestMsg { getset; }
}

using WorkflowCore.Interface;
using WorkFlowCore_Test.WorkFlows.AskForLeave.Model;
using WorkFlowCore_Test.WorkFlows.AskForLeave.Steps;
using WorkFlowCore_Test.WorkFlows.SimpleDecision.Steps;
namespaceWorkFlowCore_Test.WorkFlows.AskForLeave
{
public classAskForLeaveWorkflow : IWorkflow<LeaveRequestData>
{
publicstring Id => "LeaveRequestWorkflow";
publicint Version => 1;
publicvoidBuild(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]
publicstringWorkFlowCoreTestDemo()
{
var initialData = new LeaveRequestData
{
RequestId = "11111",
RequestMsg = "開始請假"
};
WorkflowHost.StartWorkflow("LeaveRequestWorkflow"1, initialData);
//WorkflowService.StartWorkflow("HelloWorld");
return"true";
}

然後建立一個管理員的審批方法,用來稽核透過或者拒絕。程式碼如下:

[Route("WorkFlowCoreTestDemo4")]
[HttpGet]
publicasync Task<stringWorkFlowCoreTestDemo4()
{
//獲取待決活動
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 my classType = typeof(HelloWorldStep);
//string fullAssembly className = my classType.AssemblyQualifiedName;
loader?.LoadDefinition(json, Deserializers.Json);

到這裏就可以了,建立一個api方法來呼叫看看:

[Route("WorkFlowCoreTestDemo6")]
[HttpGet]
publicstringWorkFlowCoreTestDemo6()
{
WorkflowHost.StartWorkflow("HelloWorldJson"1null);
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"
}
]
}

總結

例子備註寫的比較多,就不多贅述了。有問題的話就留言!

轉自:黃金程式設計師

連結:cnblogs.com/BFMC/p/18233359

- EOF -

推薦閱讀 點選標題可跳轉

看完本文有收獲?請轉發分享給更多人

推薦關註「DotNet」,提升.Net技能

點贊和在看就是最大的支持❤️