一个适合于.NET Core的超轻量级工作流引擎:Workflow-Core
一、关于Workflow-Core
近期工作上有一个工作流的开发需求,自己基于面向对象和职责链模式捣鼓了一套小框架,后来在github上发现一个轻量级的工作流引擎轮子:Workflow-Core,看完其wiki之后决定放弃之前自己造的轮子,使用这个开源项目来改造,也就有了这一篇博文。

Workflow-Core是一个基于.NET Standard的轻量级工作流引擎,其GitHub地址为:https://github.com/danielgerlag/workflow-core,目前有超过1200+个star。它提供了FluentAPI、多任务、持久化以及并行处理的功能,适合于小型工作流、责任链的需求开发。
由于Workflow-Core支持工作流长期运行,因此Workflow-Core支持以下多种数据源格式的持久化,可以通过安装不同的Provider包来实现对应的持久化:
- (默认提供,用于测试和开发)内存
- MongoDB
- MS SQL Server
- MySql
- Sqlite
- Redis
- PostgreSQL
立刻上手把,Nuget上安装一把,目前最新版本2.0.0:
PM> Install-Package WorkflowCore
二、Workflow-Core的基本使用
2.1 Hello World
这里创建了一个.NET Core控制台应用程序,快速演示第一个Workflow-Core的Hello World,展示如何开始一个Workflow:
(1)定义一个实现IWorkflow接口的Workflow:
public class HelloWorldWorkflow : IWorkflow
{
public string Id => "HelloWorld"; public int Version => ; public void Build(IWorkflowBuilder<object> builder)
{
builder
.StartWith<HelloWorld>()
.Then<ActiveWorld>()
.Then<GoodbyeWorld>();
}
}
这里定义了一个HelloWorldWorkflow,其版本号为1,它有3个步骤:HelloWorld、ActiveWorld和GoodbyeWorld,会依次执行。
(2)定义三个继承自StepBody类的步骤类:
public class HelloWorld : StepBody
{
public override ExecutionResult Run(IStepExecutionContext context)
{
Console.WriteLine("Hello World!");
return ExecutionResult.Next();
}
} public class ActiveWorld : StepBody
{
public override ExecutionResult Run(IStepExecutionContext context)
{
Console.WriteLine("I am activing in the World!");
return ExecutionResult.Next();
}
} public class GoodbyeWorld : StepBody
{
public override ExecutionResult Run(IStepExecutionContext context)
{
Console.WriteLine("Goodbye World!");
return ExecutionResult.Next();
}
}
(3)ServiceCollection中注入Workflow-Core相关组件
private static IServiceProvider ConfigureServices()
{
IServiceCollection services = new ServiceCollection();
services.AddLogging(); // WorkflowCore需要用到logging service
services.AddWorkflow(); var serviceProvider = services.BuildServiceProvider(); return serviceProvider;
}
(4)在Program.cs的Main方法中获取到注入的host并执行工作流
public static void Main(string[] args)
{
var serviceProvider = ConfigureServices();
var host = serviceProvider.GetService<IWorkflowHost>();
host.RegisterWorkflow<HelloWorldWorkflow>();
host.Start(); // Demo1:Hello World
host.StartWorkflow("HelloWorld"); Console.ReadKey();
host.Stop();
}
这里传入的是Workflow的Id,Workflow-Core会根据Id去自动匹配最新版本的对应Workflow,运行结果如下:

2.2 If语句
在工作流处理中,往往会有很多的条件判断,那么在Workflow-Core中也提供了直接的If功能,如下面这个IfStatementWorkflow所示:
public class IfStatementWorkflow : IWorkflow<MyData>
{
public string Id => "if-sample"; public int Version => ; public void Build(IWorkflowBuilder<MyData> builder)
{
builder
.StartWith<SayHello>()
.If(data => data.Counter < ).Do(then => then
.StartWith<PrintMessage>()
.Input(step => step.Message, data => "Outcome is less than 3")
)
.If(data => data.Counter < ).Do(then => then
.StartWith<PrintMessage>()
.Input(step => step.Message, data => "Outcome is less than 5")
)
.Then<SayGoodbye>();
}
}
这个传递进来的MyData的定义如下:
public class MyData
{
public int Counter { get; set; }
}
当传递进来的MyData的Counter属性<3 或 <5时会有不同的分支进行逻辑的处理。
2.3 MySQL持久化支持
想要将工作流配置持久化到MySQL,只需以下两步:
(1)通过Nuget安装MySQL Provider包:
PM> Install-Package WorkflowCore.Persistence.MySQL
(2)注入到ServiceCollection
services.AddWorkflow(x => x.UseMySQL(@"Server=127.0.0.1;Database=workflow;User=root;Password=password;", true, true));
一旦启动,你就会发现Workflow-Core自动帮你创建了很多表用于持久化工作流配置和实例。

2.4 计划任务和循环任务
Workflow-Core还集成了计划任务和循环任务的功能:
(1)计划任务:比如在工作流步骤中设置一个延迟5分钟执行的计划任务
builder
.StartWith(context => Console.WriteLine("Hello"))
.Schedule(data => TimeSpan.FromSeconds()).Do(schedule => schedule
.StartWith(context => Console.WriteLine("Doing scheduled tasks"))
)
.Then(context => Console.WriteLine("Doing normal tasks"));
(2)循环任务:比如在工作流步骤中设置一个延迟5分钟进行的循环任务,知道Counter > 5才结束
builder
.StartWith(context => Console.WriteLine("Hello"))
.Recur(data => TimeSpan.FromSeconds(), data => data.Counter > ).Do(recur => recur
.StartWith(context => Console.WriteLine("Doing recurring task"))
)
.Then(context => Console.WriteLine("Carry on"));
2.5 Saga支持
了解分布式事务方案的童鞋应该都知道Saga,在Workflow-Core中也有支持,这是一个十分有用的功能:
(1)比如:在创建一个客户信息之后,将其推送到Salesforce和ERP,如果推送过程中发生了错误,那么就通过重试进行补偿,并且重试有时间间隔。
builder
.StartWith<CreateCustomer>()
.Then<PushToSalesforce>()
.OnError(WorkflowErrorHandling.Retry, TimeSpan.FromMinutes())
.Then<PushToERP>()
.OnError(WorkflowErrorHandling.Retry, TimeSpan.FromMinutes());
(2)又比如:当Task2发生异常时,Workflow-Core会帮助执行UndoTask2 和 UndoTask1 帮你回滚数据以恢复状态。
builder
.StartWith<LogStart>()
.Saga(saga => saga
.StartWith<Task1>()
.CompensateWith<UndoTask1>()
.Then<Task2>()
.CompensateWith<UndoTask2>()
.Then<Task3>()
.CompensateWith<UndoTask3>()
)
.OnError(Models.WorkflowErrorHandling.Retry, TimeSpan.FromMinutes())
.Then<LogEnd>();
更多Saga示例,请参考:https://github.com/danielgerlag/workflow-core/tree/master/src/samples/WorkflowCore.Sample17
三、在ASP.NET Core中使用Workflow-Core

3.1 注入与初始化
(1)注入:使用AddWorkflow()扩展方法
public void ConfigureServices(IServiceCollection services)
{
services.AddWorkflow();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
(2)初始化:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
.......
app.UseWorkflow();
}
扩展方法如下:
public static class ConfigureExtensions
{
public static IApplicationBuilder UseWorkflow(this IApplicationBuilder app)
{
var host = app.ApplicationServices.GetService<IWorkflowHost>();
host.RegisterWorkflow<EdcWorkflow>();
host.RegisterWorkflow<EdcDataWorkflow, EdcData>();
host.Start(); var appLifetime = app.ApplicationServices.GetService<IApplicationLifetime>();
appLifetime.ApplicationStopping.Register(() =>
{
host.Stop();
}); return app;
}
}
这里需要注意的就是:将你要用到的所有Workflow都事先进行Register注册。
3.2 通过DI获取使用
在你想要用到的地方,无论是Controller还是Service,通过依赖注入获取到Host,并使用它:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private IWorkflowController _workflowService;
public ValuesController(IWorkflowController workflowService)
{
_workflowService = workflowService;
}
// GET api/values
[HttpGet]
public async Task<IEnumerable<string>> Get()
{
await _workflowService.StartWorkflow("EdcWorkflow");
return new string[] { "EdcWorkflow v1" };
}
// GET api/values/5
[HttpGet("{id}")]
public async Task<string> Get(int id)
{
await _workflowService.StartWorkflow("EdcDataWorkflow", new EdcData() { Id = id });
return "EdcDataWorkflow v1";
}
}
这两个Workflow的定义如下:
public class EdcWorkflow : IWorkflow
{
public string Id => "EdcWorkflow"; public int Version => ; public void Build(IWorkflowBuilder<object> builder)
{
builder
.StartWith<HelloWorld>()
.Then<GoodbyeWorld>();
}
} public class EdcDataWorkflow : IWorkflow<EdcData>
{
public string Id => "EdcDataWorkflow"; public int Version => ; public void Build(IWorkflowBuilder<EdcData> builder)
{
builder
.StartWith<HelloWorld>()
.If(data => data.Id < ).Do(then => then
.StartWith<PrintMessage>()
.Input(step => step.Message, data => "Passed Id is less than 3")
)
.If(data => data.Id < ).Do(then => then
.StartWith<PrintMessage>()
.Input(step => step.Message, data => "Passed Id is less than 5")
)
.Then<GoodbyeWorld>();
}
}
示例结果很简单:
(1)api/values

(2)api/values/1

四、小结
Workflow-Core是一个适合.NET Core的优秀的轻量级工作流引擎,对于小型工作流和责任链类型的需求开发很适合,可以节约大量时间避免重复造轮子,将时间主要花在业务逻辑上面。当然,这里演示的示例只是众多功能特性中的一小部分,我只是选取了我用到的部分而已,大家有兴趣的话可以去GitHub上先给个star再仔细研究其wiki文档,应用到自己的项目中去。
示例代码:https://github.com/EdisonChou/EDC.WorkflowCore.Sample
一个适合于.NET Core的超轻量级工作流引擎:Workflow-Core的更多相关文章
- 开源工作流引擎 Workflow Core 的研究和使用教程
目录 开源工作流引擎 Workflow Core 的研究和使用教程 一,工作流对象和使用前说明 二,IStepBuilder 节点 三,工作流节点的逻辑和操作 容器操作 普通节点 事件 条件体和循环体 ...
- 基于领域驱动设计(DDD)超轻量级快速开发架构
smartadmin.core.urf 这个项目是基于asp.net core 3.1(最新)基础上参照领域驱动设计(DDD)的理念,并参考目前最为了流行的abp架构开发的一套轻量级的快速开发web ...
- 分享自己的超轻量级高性能ORM数据访问框架Deft
Deft 简介 Deft是一个超轻量级高性能O/R mapping数据访问框架,简单易用,几分钟即可上手. Deft包含如下但不限于此的特点: 1.按照Transact-SQL的语法语义风格来设计,只 ...
- 超轻量级高性能ORM数据访问组件Deft,比dapper快20%以上
超轻量级高性能ORM数据访问组件Deft,比dapper快20%以上 阅读目录 Deft简介 Deft 核心类介绍 Deft 3分钟即可上手使用 其他可选的配置参数 性能测试 Demo代码下载 回到顶 ...
- 基于Groovy+HttpRestful的超轻量级的接口测试用例配置的设计方案及DEMO实现
目标 设计一个轻量级测试用例框架,接口测试编写者只需要编写测试用例相关的内容(入参及结果校验),不需要理会系统的实现,不需要写跟测试校验无关的内容. 思路 测试用例分析 一个用例由以下部分组成: (1 ...
- 聊聊如何设计千万级吞吐量的.Net Core网络通信!
聊聊如何设计千万级吞吐量的.Net Core网络通信! 作者:大石头 时间:2018-10-26 晚上 20:00 地点:QQ群-1600800 内容:网络通信, 网络库使用方式 网络库设计理念,高性 ...
- 跨平台移动开发 Xuijs超轻量级的框架Style CSS属性用法
PhoneGap里面推荐使用的超轻量级的框架 Style CSS属性用法 设置css属性:setstyle 通过ID设置css属性 x$('#top1').setStyle('color', '#DB ...
- 超轻量级网络SqueezeNet网络解读
SqueezeNet网络模型非常小,但分类精度接近AlexNet. 这里复习一下卷积层参数的计算 输入通道ci,核尺寸k,输出通道co,参数个数为: 以AlexNet第一个卷积为例,参数量达到:3*1 ...
- 基于领域驱动设计(DDD)超轻量级快速开发架构(二)动态linq查询的实现方式
-之动态查询,查询逻辑封装复用 基于领域驱动设计(DDD)超轻量级快速开发架构详细介绍请看 https://www.cnblogs.com/neozhu/p/13174234.html 需求 配合Ea ...
随机推荐
- 【赠书】300- 59篇原创带你进入 JavaScript 生态圈
点击上方"前端自习课"关注,学习起来~ 不知不觉,[前端自习课]已经连续推送300天整(不含删除的文章),每天一篇,正如公众号的 Slogan:每日清晨,享受一篇前端优秀文章. 运 ...
- java8-从Lamda到方法引用和构造引用
一方法引用概述 经过前面2章Lamda原理引入和Lamda解析,基本就会熟练使用Lamda表达式,这次我们更深入点.来了解一下方法引用. 方法引用是特定Lamda表达式的一种简写,其思路就是能替换La ...
- cuckoo沙箱技术分析全景图
从事信息安全技术行业的小伙伴们都知道沙箱技术(有些也称沙盒),用来判断一个程序或者文件是否是恶意的病毒.木马.漏洞攻击exp或其他恶意软件.其原理简单来说就是提供了一个虚拟的环境,把分析目标放到这个虚 ...
- asp.net core 3.0 MVC JSON 全局配置
asp.net core 3.0 MVC JSON 全局配置 System.Text.Json(default) startup配置代码如下: using System.Text.Encodings. ...
- HTML连载57-相对定位和绝对定位
一.定位流 1.分类 (1)相对定位: (2)绝对定位 (3)固定定位 (4)静态定位 2.什么相对定位 相对定位就是相对于自己以前在标准流中的位置来移动. 例子: <style> div ...
- Redis学习(二)Redis的安装
Window 下安装 下载地址:https://github.com/MSOpenTech/redis/releases. Redis 支持 32 位和 64 位.这个需要根据你系统平台的实际情况选择 ...
- 第1章:C++泛型技术基础:模板——《C++泛型:STL原理和应用》读书笔记整理
第1章:C++泛型技术基础:模板 1.2 关于模板参数 1.2.1 模板参数类型 类型参数 typename声明的参数都属于类型参数,它的实参必须为系统内置或者用户自定义的数据类型,包括类模板实体 ...
- Graylog 笔记
安装 基本上有3种方式,1 yum安装2 rpm安装3 docker安装 yum安装 yum安装,参照官方文档是最好的:http://docs.graylog.org/en/3.0/pages/ins ...
- Spring Cloud进阶之路 | 一:服务注册与发现(nacos)
转载请注明作者及出处: 作者:银河架构师 原文链接:https://www.cnblogs.com/luas/p/12068846.html 1.版本 最新稳定版本为1.1.4,也可以从发版说明.博客 ...
- Java 程序员最喜欢使用的日常工具
多年来,Java 始终是企业应用程序的支柱.最近几年,Java 也是 Android 开发的首选编程语言.不过开发人员如何使用这种语言呢?一项新的研究阐明了主要使用 Java 的开发人员的工作类型,以 ...