This technology is used by webmasters in their work, so I am republishing this article so everyone can understand what workflow is and what it can be used for.
The article is as follows:
Recently, I wanted to develop an OA-related website. I had heard about workflow for a long time and had previously studied Workflow Foundation 4.0 on and off, but I still couldn't figure out exactly what it could be used for.
Nevertheless, I felt that workflow should be applicable in certain scenarios. Although I still didn't have an answer, I searched online and found something called workflow-core. It seemed interesting, so I stopped to explore it. Now I would like to share it with you.
Introduction
Workflow Core GitHub homepage: https://github.com/danielgerlag/workflow-core
As introduced on the homepage, Workflow Core is a lightweight workflow engine that can be embedded into projects. It is developed on .NET Standard 2.0 and can be used to track the state of long-running tasks. It is quite powerful, supports plug-in persistence, and parallel processing of multiple nodes, which seems impressive. There is also a Conductor project that uses Workflow Core as its core workflow server (it turns out running a workflow requires a separate server). I won't go into Conductor here. Workflow Core supports fluent syntax, making it very elegant to write. Although it lacks the graphical interface of WF, the code feels cleaner.
- Interlude: Introduction to .NET Standard 2.0
At first, I didn't understand what .NET Standard 2.0 was. This article explains it clearly: Relationship between .NET Standard and .NET Framework, and also this one: Is .NET Core 2.0 Your Best Choice?. It turns out that Microsoft created the .NET Standard library to unify various .NET platforms. Projects developed based on this library can be applied to .NET Framework 4.6.1 and above, as well as .NET Core 2.0 and above.
After understanding the relevant content, I directly opened the documentation and followed the examples.
Example 1
Create a new project, specifying .NET Framework 4.6.1 or higher. After creating the project, install Workflow Core in the Package Manager Console: Install-Package WorkflowCore. This package will install a series of dependent packages by default.
Due to version dependencies, you might also need to install two additional packages: Microsoft.Extensions.Logging and Microsoft.Extensions.Logging.Debug. After that, you can start writing code according to Sample 01.

Sample 01 is a HelloWorld, which consists of several parts:
- Building StepBody – this is the content to be executed in the workflow. Each class inherits from the abstract class
StepBodyand overrides theExecutionResult Run(IStepExecutionContext context)method to complete the required work.
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();
}
}
- Building the workflow – implement the
IWorkflowinterface. Each workflow has anIdand aVersionto identify it. Here, two methods are used to buildHelloWorkflow.
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>();
}
}
- Everything is ready – now let's run the workflow. The first step is to set up the service. Workflow Core adds workflow-related services through the
ServiceCollectionin theInjectionnamespace. ForStepBodyclasses that have parameters, they need to be registered using theAddTransientmethod of the service so that the objects can be constructed correctly:
/// <summary>
/// Configure 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"));
// These constructors have parameters, so they need to be added to 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 and start a workflow instance. I'll paste the entire form code for clarity:
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");
// If the host has already started, it cannot be started again, but there is no method to check
if (!_serviceStarted)
{
host.Start();
_serviceStarted = true;
}
// Start the workflow
host.StartWorkflow("HelloWorkflow", 1, data: null); //
//host.StartWorkflow("HelloWorkflow");//, 2, data: null, will default to the higher version
}
private void StopWorkflow()
{
var host = _serviceProvider.GetService<IWorkflowHost>();
host?.Stop();
_serviceStarted = false;
}
/// <summary>
/// Configure 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"));
// These constructors have parameters, so they need to be added to 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();
}
}
And that's it for a simple Workflow Core example. Overall, it's quite simple and clear.
This article is a repost.
Author: Jimmy.Tang
Original title: A Super Lightweight Workflow Engine for .NET Core: Workflow-Core
Original link: https://www.cnblogs.com/keep-study-to-die/p/12001408.html
Note from webmaster: The code in the article actually references many packages, but the original text did not list them all. When I tested it, I added all the missing packages. Test code can be found at: https://github.com/dotnet9/TerminalMACS.ManagerForWPF/tree/master/src/Demo/WorkflowTest