站長工作中會使用到該技術,所以轉載該篇文章,大家一起了解 workflow,能夠用它做什麼。
文章正文如下:
最近想做一個 oa 相關的網站開發,一直都聽說有 workflow 的東西,之前也斷斷續續學習過 workflow foundation 4.0,還是沒有搞明白到底能夠用它做什麼。
但還是覺得 workflow 在某種情形下應該可以適用,雖然還沒有答案,網上搜樓了一通,發現一個 workflow-core 的東西,覺得挺有意思,遂停下來,琢磨一下,現分享與大家。
簡介
workflow core 的 github 主頁:https://github.com/danielgerlag/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,包含了幾部分內容:
- 构建 StepBody,就是 workflow 中需要执行的内容,每个类继承自 StepBody 这个虚拟类,重载
ExecutionResult Run(IStepExecutionContext context),这个函数中完成所需的工作
public class HelloWorld : StepBody
{
private ILogger logger;
public HelloWorld(ILoggerFactory loggerFactory)
{
logger = loggerFactory.CreateLogger<HelloWorld>();
}
public override ExecutionResult Run(IStepExecutionContext context)
{
Console.WriteLine("Hello world, workflow");
logger.LogInformation("Helloworld workflow");
return ExecutionResult.Next();
}
}
public class GoodbyeWorld : StepBody
{
private ILogger logger;
public GoodbyeWorld(ILoggerFactory loggerFactory)
{
logger = loggerFactory.CreateLogger<GoodbyeWorld>();
}
public override ExecutionResult Run(IStepExecutionContext context)
{
Console.WriteLine("Workflow, Goodbye");
logger.LogInformation("Goodbye workflow");
return ExecutionResult.Next();
}
}
public class SleepStep : StepBody
{
private ILogger logger;
public SleepStep(ILoggerFactory loggerFactory)
{
logger = loggerFactory.CreateLogger("SleepStep");
}
public override ExecutionResult Run(IStepExecutionContext context)
{
Thread.Sleep(1000);
logger.LogInformation("Sleeped");
return ExecutionResult.Next();
}
}
- 構建 workflow,實現 iworkflow 接口,每個 workflow 有一個 id 和一個 version,標明這個 workflow 的身份,這裡通過兩種方法構建了 helloworkflow,
public class HelloWorkflow : IWorkflow
{
public string Id => "HelloWorkflow";
public int Version => 1;
public void Build(IWorkflowBuilder<object> builder)
{
builder.StartWith(context =>
{
Console.WriteLine("Hello world");
return ExecutionResult.Next();
})
.Then(context =>
{
Thread.Sleep(500);
Console.WriteLine("sleeped");
return ExecutionResult.Next();
})
.Then(context =>
{
Console.WriteLine("Goodbye world");
return ExecutionResult.Next();
});
}
}
public class HelloWorkflow2 : IWorkflow
{
public string Id => "HelloWorkflow";
public int Version => 2;
public void Build(IWorkflowBuilder<object> builder)
{
builder.StartWith<HelloWorld>()
.Then<SleepStep>()
.Then<GoodbyeWorld>();
}
}
- 萬事俱備,準備讓 workflow 運行起來。第一步當然是需要搭建 service,workflow core 通過 injection 命名空間的 servicecollection 添加了 workflow 相關的服務,對於有參數的 stepbody,需要先通過 service 的 addtransient 函數註冊,這樣才能正確的構造對象:
/// <summary>
/// 配置workflow
/// </summary>
/// <returns></returns>
private IServiceProvider ConfigureServices()
{
//setup dependency injection
IServiceCollection services = new ServiceCollection();
services.AddLogging();
services.AddWorkflow();
//services.AddWorkflow(x => x.UseMongoDB(@"mongodb://localhost:27017", "workflow"));
// 这些个构造函数带参数的,需要添加到transient中
services.AddTransient<HelloWorld>();
services.AddTransient<GoodbyeWorld>();
services.AddTransient<SleepStep>();
var serviceProvider = services.BuildServiceProvider();
//config logging
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
loggerFactory?.AddProvider(new DebugLoggerProvider());
return serviceProvider;
}
接下來,啟動 workflow 主機,並啟動一次 workflow,將整個窗體代碼貼一下,這樣比較清晰
using Microsoft.Extensions.DependencyInjection;
using System.Windows;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Debug;
using WorkflowCore.Interface;
namespace WorkflowTest;
public partial class MainWindow : Window
{
IServiceProvider? _serviceProvider = null;
bool _serviceStarted = false;
public MainWindow()
{
InitializeComponent();
}
private void StartWorkflow()
{
if (_serviceProvider == null)
{
_serviceProvider = ConfigureServices();
var host1 = _serviceProvider.GetService<IWorkflowHost>();
host1?.RegisterWorkflow<HelloWorkflow>();
host1?.RegisterWorkflow<HelloWorkflow2>();
}
var host = _serviceProvider.GetService<IWorkflowHost>();
var wd = host.Registry.GetDefinition("HelloWorkflow");
// 如果host启动了,不能再次启动,但没有判断方法
if (!_serviceStarted)
{
host.Start();
_serviceStarted = true;
}
// 启动workflow工作流
host.StartWorkflow("HelloWorkflow", 1, data: null); //
//host.StartWorkflow("HelloWorkflow");//, 2, data: null, 默认会启用版本高的
}
private void StopWorkflow()
{
var host = _serviceProvider.GetService<IWorkflowHost>();
host?.Stop();
_serviceStarted = false;
}
/// <summary>
/// 配置workflow
/// </summary>
/// <returns></returns>
private IServiceProvider ConfigureServices()
{
//setup dependency injection
IServiceCollection services = new ServiceCollection();
services.AddLogging();
services.AddWorkflow();
//services.AddWorkflow(x => x.UseMongoDB(@"mongodb://localhost:27017", "workflow"));
// 这些个构造函数带参数的,需要添加到transient中
services.AddTransient<HelloWorld>();
services.AddTransient<GoodbyeWorld>();
services.AddTransient<SleepStep>();
var serviceProvider = services.BuildServiceProvider();
//config logging
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
loggerFactory?.AddProvider(new DebugLoggerProvider());
return serviceProvider;
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
StartWorkflow();
}
private void stopButton_Click(object sender, RoutedEventArgs e)
{
StopWorkflow();
}
}
就這樣一個簡單的 workflow core 例子就完成了,總體來說,還是很簡單,清晰的。
本文來自轉載。
作者:jimmy.tang
原文標題:一個適合於.net core 的超輕量級工作流引擎:workflow-core
原文連結:https://www.cnblogs.com/keep-study-to-die/p/12001408.html
站长注:文中代码其实引用了不少包,但原文未说全,站长测试时已将包补全,测试代码见:https://github.com/dotnet9/TerminalMACS.ManagerForWPF/tree/master/src/Demo/WorkflowTest