一个适合于.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 => 1;

        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 => 1;

        public void Build(IWorkflowBuilder<MyData> builder)
        {
            builder
                .StartWith<SayHello>()
                .If(data => data.Counter < 3).Do(then => then
                        .StartWith<PrintMessage>()
                            .Input(step => step.Message, data => "Outcome is less than 3")
                )
               .If(data => data.Counter < 5).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(5)).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(5), data => data.Counter > 5).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(10))
            .Then<PushToERP>()
                .OnError(WorkflowErrorHandling.Retry, TimeSpan.FromMinutes(10));

  (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(10))
    .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 => 1;

        public void Build(IWorkflowBuilder<object> builder)
        {
            builder
                .StartWith<HelloWorld>()
                .Then<GoodbyeWorld>();
        }
    }

    public class EdcDataWorkflow : IWorkflow<EdcData>
    {
        public string Id => "EdcDataWorkflow";

        public int Version => 1;

        public void Build(IWorkflowBuilder<EdcData> builder)
        {
            builder
                .StartWith<HelloWorld>()
                .If(data => data.Id < 3).Do(then => then
                        .StartWith<PrintMessage>()
                            .Input(step => step.Message, data => "Passed Id is less than 3")
                )
               .If(data => data.Id < 5).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

原文地址:https://www.cnblogs.com/xbzhu/p/11610797.html

时间: 2025-01-09 18:44:00

一个适合于.NET Core的超轻量级工作流引擎:Workflow-Core的相关文章

开源工作流引擎 Workflow Core 的研究和使用教程

目录 开源工作流引擎 Workflow Core 的研究和使用教程 一,工作流对象和使用前说明 二,IStepBuilder 节点 三,工作流节点的逻辑和操作 容器操作 普通节点 事件 条件体和循环体 节点的异步或多线程 用于事务的操作 四,条件或开关 迭代 条件判断 节点并发 五,其它 开源工作流引擎 Workflow Core 的研究和使用教程 一,工作流对象和使用前说明 为了避免歧义,事先约定. 工作流有很多节点组成,一个节点成为步骤点(Step). 1,IWorkflow / IWork

NicEditor——超轻量级文本编辑器

NicEdit是一个轻量级,跨平台的Inline Content Editor.NicEdit能够让任何 element/div变成可编辑或者能够把标准的TextArea转换成富文本编辑器. 相较于以前用过的FreeTextBox,NicEdit更加的轻便,其轻量级的程度--总共就一个JS文件和一张图片,而且使用也十分简单.引用下载好的JS文件,然后调用相应的JS函数,将TextBox控件转变成富文本编辑器. 英文本: <span style="font-size:14px;"&

自己编写的 C++ 超轻量级日志类

[自己编写的 C++ 超轻量级日志类(兼容vc++6.0.vs2010.vs2015)] 先来看效果: [测试文件:test.cpp] /* 作者:闫文山 时间:2017/07/02 介绍: 本日志类功能强大: 1.小巧可爱,全程序(YLog.h+YLog.cpp)不过一百余行而已,比之网上其他的如log4cpp等堪称超轻量级: 2.可输出每条日志信息的日志级别.输出时间(可精确到毫秒级).所在程序文件名.所在行数.日志信息(支持可变长.标准格式化 %s,%d,%f 等参数): 3.兼容性强大,

大流量网站性能优化:一步一步打造一个适合自己的BigRender插件(转)

BigRender 当一个网站越来越庞大,加载速度越来越慢的时候,开发者们不得不对其进行优化,谁愿意访问一个需要等待 10 秒,20 秒才能出现的网页呢? 常见的也是相对简单易行的一个优化方案是 图片的延迟加载.一个庞大的页面,有时我们并不会滚动去看下面的内容,这样就浪费了非首屏部分的渲染,而这些无用的渲染,不仅包括图片,还包括其他的 DOM 元素,甚至一些 js/css(某些js/css 是根据模块请求的,比如一些 ajax),理论上,每增加一个 DOM,都会增加渲染的时间.有没有办法能使得

结合当前公司发展情况,技术团队情况,设计一个适合的技术团队绩效考核机制

结合当前公司发展情况,技术团队情况,设计一个适合的技术团队绩效考核机制 一.引言 要想制定绩效考核机制首先要先知道绩效考核的定义是什么,绩效考核指企业在既定的战略目标下,运用特定的标准和指标,对员工的工作行为及取得的工作业绩进行评估,并运用评估的结果对员工将来的工作行为和工作业绩产生正面引导的过程和方法. 绩效考核(performance evaluation),是企业绩效管理中的一个环节,常见绩效考核方法包括bsc.kpi及360度考核等.绩效考核是一项系统工程.绩效考核是绩效管理过程中的一种

js页码生成库,一个适合前后端分离的页码生成器

原文:js页码生成库,一个适合前后端分离的页码生成器 前言 上星期写的任务里面有需要进行分页的处理,git搜索了一番,没有觉得合适的,于是自己临时写了个分页的算法. 然后等闲下来的时候,决定把分页进行优化并推广.于是乎,一个适合前后端分离的页码生成器就这样出来了. 先别废话了,直接上 git 地址 和 demo 地址.看官果断点击进去瞧瞧看.项目主页的 readme 文档的自动排版将更好. 先讲讲设计思想 整个开发流程围绕事件绑定进行开发. 脱离 callback 回调这种回调方法,直接使用 事

教师课堂教学必备的100个妙招,总有一个适合你!

教师课堂教学必备的100个妙招,总有一个适合你! 转自:郝任工作室 4天前 1 微笑中,拉近师生的心 教师的微笑有着无穷的魅力.教师的微笑能调节课堂情绪,增进师生情谊,激发学生的学习的热情,增强其自信力. 2 了解中,调动学生学习积极性 教师了解了学生,就会体谅学生,就会让学生感受到教师给以的尊重,学生自然也会还以尊重,专心投入到课堂学习中. 3 自然中,课堂教学精彩无痕 最好的课前交流,是教师与学生自然的谈话,并不露痕迹地将学生引入新课的学习中,为精彩教学做准备. 4 亲近中,真情打动学生的心

使用特性+反射来做超轻量级的定时调度服务

1.定义特性,特性中包含执行间隔的属性,在每个需要定时调度执行的方法上加上该特性,表示该方法参与定时调度. 2.编写方法,默认在调度服务启动时,会先访问该方法来获取全部需要定时执行的方法和间隔: 3.每个方法执行时,可以向服务返回日志,同时也可以返回下次执行的时间,服务将在指定的时间来调用该服务,默认按调度规则执行.若需要额外指定下次执行的时间可以在返回值中执行: 4.其实可以考虑增加本次调度的间隔参数,以方便被调用服务判断当前执行的间隔是否是常规间隔还是自定义间隔. -------------

ASP.NET Core 入门教程 7、ASP.NET Core MVC 分部视图入门

原文:ASP.NET Core 入门教程 7.ASP.NET Core MVC 分部视图入门 一.前言 1.本教程主要内容 ASP.NET Core MVC (Razor)分部视图简介 ASP.NET Core MVC (Razor)分部视图基础教程 ASP.NET Core MVC (Razor)强类型分部视图教程 2.本教程环境信息 软件/环境 说明 操作系统 Windows 10 SDK 2.1.401 ASP.NET Core 2.1.3 IDE Visual Studio Code 1