最近想做一个OA相关的网站开发,一直都听说有workflow的东西,之前也断断续续学习过 Workflow Foundation 4.0,还是没有搞明白到底能够用它做什么
但还是觉得workflow在某种情形下应该可以适用,虽然还没有答案,网上搜楼了一通,发现一个workflow-core的东西,觉得挺有意思,遂停下来,琢磨一下,现分享与大家。
* 简介
如主页上介绍的,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开始编写代码了

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

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 }
2. 构建workflow,实现IWorkflow接口,每个workflow有一个Id和一个Version,标明这个workflow的身份,这里通过两种方法构建了HelloWorkflow,

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

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 }
接下来,启动workflow 主机,并启动一次workflow,将整个窗体代码贴一下,这样比较清晰

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 }
就这样一个简单的Workflow Core例子就完成了,总体来说,还是很简单,清晰的。
来源:https://www.cnblogs.com/keep-study-to-die/p/12001408.html
