An ultra-lightweight workflow engine for. NET Core: Workflow-Core

An ultra-lightweight workflow engine for. NET Core: Workflow-Core

I heard that there is a workflow thing, but I didn't understand what I could do with it.

最后更新 2/6/2023 10:36 PM
Jimmy.Tang
预计阅读 7 分钟
分类
.NET
标签
.NET C#

Webmasters will use this technology in their work, so reprint this article so that everyone can understand workflow and what they can do with it.

The main body of the article is as follows:


Recently, I wanted to do an OA-related website development. I have always heard about workflow. I have studied Workflow Foundation 4.0 intermittently before, but I still don't understand what I can do with it.

But I still think workflow should be applicable in certain situations. Although there is no answer yet, I searched the Internet and found a workflow-core thing. I thought it was quite interesting, so I stopped, thought about it, and now shared it with everyone.

profile

GitHub homepage of workflow core: github.com/danielgerlag/workflow-core

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

  • Introduction to. 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 以上。

After understanding the relevant content, I directly opened the instructions and followed the example.

Examples 1

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

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

Sample01 is a helloworld that contains several parts:

  1. 构建 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();
    }
}
  1. Build workflows and implement the IWorkflow interface. Each workflow has an Id and a Version to identify the identity of the workflow. Here, HelloWorkflow is built through two methods.
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>();
    }
}
  1. Everything is ready to get workflow running. The first step is of course to build a service. Workflow Core adds Workflow-related services through ServiceCollection in the Injection namespace. For StepBody with parameters, you need to first register through the service's AddTransient function, so that the object can be correctly constructed:
/// <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;
}

Next, start the workflow host, start the workflow once, and paste the entire form code to make it clearer

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();
    }
}

Just like this, a simple Workflow Core example is completed. Overall, it is still very simple and clear.

This article comes from reprint.

Author: Jimmy Tang

Original title: An ultra-lightweight workflow engine suitable for. NET Core: Workflow-Core

Original link: www.cnblogs.com/keep-study-to-die/p/12001408.html

站长注:文中代码其实引用了不少包,但原文未说全,站长测试时已将包补全,测试代码见:https://github.com/dotnet9/TerminalMACS.ManagerForWPF/tree/master/src/Demo/WorkflowTest

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 4/22/2026

Support for. NET by operating system versions (250707 update)

Use virtual machines and test machines to test the support of each version of the operating system for. NET. After installing the operating system, it is passed by measuring the corresponding running time of the installation and being able to run the Stardust Agent.

继续阅读
同分类 / 同标签 2/7/2026

Summary of experience in using AOT

From the very beginning of project creation, you should develop a good habit of conducting AOT release testing in a timely manner whenever new features are added or newer syntax is used.

继续阅读