workflow-core 简介

 最近想做一个OA相关的网站开发,一直都听说有workflow的东西,之前也断断续续学习过 Workflow Foundation 4.0,还是没有搞明白到底能够用它做什么

 但还是觉得workflow在某种情形下应该可以适用,虽然还没有答案,网上搜楼了一通,发现一个workflow-core的东西,觉得挺有意思,遂停下来,琢磨一下,现分享与大家。

 

 * 简介

workflow core的GitHub主页

如主页上介绍的,workflow core作为一个轻量级workflow引擎,可以嵌入到项目中,其底层是用.net standard 2.0开发,可以用来追踪长时间运行的任务状态,功能也比较强大,支持插件形式持久化,和多节点并行处理,貌似很牛。并且目前有给一个 Conductor 项目,就是使用workflow core作为内核的workflow服务器(原来运行workflow,需要单独的一个服务器啊),Conductor这里就不展开了。workflow core支持fluent语法,写起来也非常美观,虽然没有WF那样有图形化的操作界面,但感觉代码比较干净。

- 插播.Net Standard 2.0 简介

开始的时候不了解什么是.Net Standard 2.0,这篇文章讲得比较清楚,.Net Standard 与 .Net Framework关系 还有这个.NET Core 2.0 是您的最好选择吗,原来微软为了统一.Net 的各种平台,出了一个.Net Standard 标准库,基于这个库开发的,可以应用于.net framework 4.6.1以上版本,也可以应用于.net core 2.0以上

了解了相关内容后,直接打开说明,照着例子走一遭了。

 

* 示例1

新建一个项目,指明使用.net framework 4.6.1以上,新建项目后,在Package Manager Console中,安装workflow core:Install-Package WorkflowCore,安装这个包会默认安装一系列的依赖包

可能由于版本的关系,还需要另外安装两个包:Microsoft.Extensions.Logging 和 Microsoft.Extensions.Logging.Debug。这样就可以按照Sample 01开始编写代码了

workflow-core 简介

 

Sample01是一个helloworld,包含了几部分内容:

1. 构建StepBody,就是workflow中需要执行的内容,每个类继承自StepBody这个虚拟类,重载ExecutionResult Run(IStepExecutionContext context),这个函数中完成所需的工作

workflow-core 简介
 1     public class HelloWorld : StepBody
 2     {
 3         private ILogger logger;
 4 
 5         public HelloWorld(ILoggerFactory loggerFactory)
 6         {
 7             logger = loggerFactory.CreateLogger<HelloWorld>();
 8         }
 9 
10         public override ExecutionResult Run(IStepExecutionContext context)
11         {
12             Console.WriteLine("Hello world, workflow");
13             logger.LogInformation("Helloworld workflow");
14 
15             return ExecutionResult.Next();
16         }
17     }
18 
19 
20     public class GoodbyeWorld : StepBody
21     {
22         private ILogger logger;
23 
24         public GoodbyeWorld(ILoggerFactory loggerFactory)
25         {
26             logger = loggerFactory.CreateLogger<GoodbyeWorld>();
27         }
28 
29         public override ExecutionResult Run(IStepExecutionContext context)
30         {
31             Console.WriteLine("Workflow, Goodbye");
32             logger.LogInformation("Goodbye workflow");
33 
34             return ExecutionResult.Next();
35         }
36     }
37 
38     public class SleepStep : StepBody
39     {
40         private ILogger logger;
41 
42         public SleepStep(ILoggerFactory loggerFactory)
43         {
44             logger = loggerFactory.CreateLogger("SleepStep");
45         }
46 
47         public override ExecutionResult Run(IStepExecutionContext context)
48         {
49             Thread.Sleep(1000);
50 
51             logger.LogInformation("Sleeped");
52 
53             return ExecutionResult.Next();
54         }
55     }
View Code

2. 构建workflow,实现IWorkflow接口,每个workflow有一个Id和一个Version,标明这个workflow的身份,这里通过两种方法构建了HelloWorkflow,

workflow-core 简介
 1     public class HelloWorkflow : IWorkflow
 2     {
 3         public string Id => "HelloWorkflow";
 4 
 5         public int Version => 1;
 6 
 7         public void Build(IWorkflowBuilder<object> builder)
 8         {
 9             builder.StartWith(context =>
10             {
11                 Console.WriteLine("Hello world");
12                 return ExecutionResult.Next();
13             })
14             .Then(context =>
15             {
16                 Thread.Sleep(500);
17                 Console.WriteLine("sleeped");
18                 return ExecutionResult.Next();
19             })
20             .Then(context =>
21             {
22                 Console.WriteLine("Goodbye world");
23                 return ExecutionResult.Next();
24             });
25         }
26     }
27 
28     public class HelloWorkflow2 : IWorkflow
29     {
30         public string Id => "HelloWorkflow";
31 
32         public int Version => 2;
33 
34         public void Build(IWorkflowBuilder<object> builder)
35         {
36             builder.StartWith<HelloWorld>()
37                 .Then<SleepStep>()
38                 .Then<GoodbyeWorld>();
39         }
40     }
HelloWorkflow

3. 万事俱备,准备让workflow运行起来。第一步当然是需要搭建service,Workflow Core通过Injection命名空间的ServiceCollection添加了Workflow相关的服务,对于有参数的StepBody,需要先通过service的AddTransient函数注册,这样才能正确的构造对象

workflow-core 简介
 1         /// <summary>
 2         /// 配置workflow
 3         /// </summary>
 4         /// <returns></returns>
 5         private IServiceProvider ConfigureServices()
 6         {
 7             //setup dependency injection
 8             IServiceCollection services = new ServiceCollection();
 9             services.AddLogging();
10             services.AddWorkflow();
11             //services.AddWorkflow(x => x.UseMongoDB(@"mongodb://localhost:27017", "workflow"));
12 
13             // 这些个构造函数带参数的,需要添加到transient中
14             services.AddTransient<HelloWorld>();
15             services.AddTransient<GoodbyeWorld>();
16             services.AddTransient<SleepStep>();
17 
18             var serviceProvider = services.BuildServiceProvider();
19 
20             //config logging
21             var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
22             loggerFactory.AddProvider(new DebugLoggerProvider());
23 
24             return serviceProvider;
25         }
构建Service

接下来,启动workflow 主机,并启动一次workflow,将整个窗体代码贴一下,这样比较清晰

workflow-core 简介
  1 using Microsoft.Extensions.DependencyInjection;
  2 using Microsoft.Extensions.Logging;
  3 using Microsoft.Extensions.Logging.Console;
  4 using Microsoft.Extensions.Logging.Debug;
  5 using System;
  6 using System.Collections.Generic;
  7 using System.Linq;
  8 using System.Text;
  9 using System.Threading.Tasks;
 10 using System.Windows;
 11 using System.Windows.Controls;
 12 using System.Windows.Data;
 13 using System.Windows.Documents;
 14 using System.Windows.Input;
 15 using System.Windows.Media;
 16 using System.Windows.Media.Imaging;
 17 using System.Windows.Navigation;
 18 using System.Windows.Shapes;
 19 using WorkflowCore.Interface;
 20 using WorkflowCore.Services;
 21 using WorkFlowCoreTest.MyWorkflow;
 22 
 23 namespace WorkFlowCoreTest
 24 {
 25     /// <summary>
 26     /// Interaction logic for MainWindow.xaml
 27     /// </summary>
 28     public partial class MainWindow : Window
 29     {
 30         IServiceProvider serviceProvider = null;
 31         bool serviceStarted = false;
 32 
 33         public MainWindow()
 34         {
 35             InitializeComponent();
 36         }
 37 
 38         private void StartWorkflow()
 39         {
 40 
 41             if (serviceProvider == null)
 42             {
 43                 serviceProvider = ConfigureServices();
 44                 var host1 = serviceProvider.GetService<IWorkflowHost>();
 45 
 46                 host1.RegisterWorkflow<HelloWorkflow>();
 47                 host1.RegisterWorkflow<HelloWorkflow2>();
 48             }
 49 
 50 
 51             var host = serviceProvider.GetService<IWorkflowHost>();
 52             var wd = host.Registry.GetDefinition("HelloWorkflow");
 53 
 54             // 如果host启动了,不能再次启动,但没有判断方法
 55             if (!serviceStarted)
 56             {
 57                 host.Start();
 58                 serviceStarted = true;
 59             }
 60             
 61 
 62             // 启动workflow工作流
 63             host.StartWorkflow("HelloWorkflow", 1, data: null); //
 64             //host.StartWorkflow("HelloWorkflow");//, 2, data: null, 默认会启用版本高的
 65         }
 66 
 67         private void StopWorkflow()
 68         {
 69             var host = serviceProvider.GetService<IWorkflowHost>();
 70 
 71             host.Stop();
 72             serviceStarted = false;
 73         }
 74 
 75         /// <summary>
 76         /// 配置workflow
 77         /// </summary>
 78         /// <returns></returns>
 79         private IServiceProvider ConfigureServices()
 80         {
 81             //setup dependency injection
 82             IServiceCollection services = new ServiceCollection();
 83             services.AddLogging();
 84             services.AddWorkflow();
 85             //services.AddWorkflow(x => x.UseMongoDB(@"mongodb://localhost:27017", "workflow"));
 86 
 87             // 这些个构造函数带参数的,需要添加到transient中
 88             services.AddTransient<HelloWorld>();
 89             services.AddTransient<GoodbyeWorld>();
 90             services.AddTransient<SleepStep>();
 91 
 92             var serviceProvider = services.BuildServiceProvider();
 93 
 94             //config logging
 95             var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
 96             loggerFactory.AddProvider(new DebugLoggerProvider());
 97 
 98             return serviceProvider;
 99         }
100 
101         private void startButton_Click(object sender, RoutedEventArgs e)
102         {
103             StartWorkflow();
104         }
105 
106         private void stopButton_Click(object sender, RoutedEventArgs e)
107         {
108             StopWorkflow();
109         }
110     }
111 }
View Code

 

就这样一个简单的Workflow Core例子就完成了,总体来说,还是很简单,清晰的。

 

 

 

 

上一篇:asp.net core 通过自定义容器获取DI容器中的类型


下一篇:.NetCore学习笔记:四、AutoMapper对象映射