1.WokflowCore之基础概念

步骤(step)

工作流由一系列相连的步骤组成,每个步骤都可以有输入和输出,这些输出也可以传递到它所在的工作流。可以通过StepBodyStepBodyAsync抽象类来创建步骤并实现Run/RunAsync方法,该方法也可以在定义工作流的时候内联创建。

public class HelloWorld : StepBody
{
    public override ExecutionResult Run(IStepExecutionContext context)
    {
        Console.WriteLine("Hello world");
        return ExecutionResult.Next();
    }
}

StepBodyStepBodyAsync是由WrokflowCore宿主创建,在创建的时候首先尝试使用IServiceProvider进行依赖注入,如果无法使用则搜索无参构造函数。

工作流

通过组成一系列步骤来组成工作流,通过实现IWorkflow接口来实现

public class HelloWorldWorkflow : IWorkflow
{
    public string Id => "HelloWorld";
    public int Version => 1;

    public void Build(IWorkflowBuilder<object> builder)
    {
        builder
            .StartWith<HelloWorld>()
            .Then<GoodbyeWorld>();
    }  
}

使用内联方式定义

public class HelloWorldWorkflow : IWorkflow
{
    public string Id => "HelloWorld";
    public int Version => 1;

    public void Build(IWorkflowBuilder<object> builder)
    {
        builder
            .StartWith(context =>
            {
                //内联定义
                Console.WriteLine("Hello world");
                return ExecutionResult.Next();
            })
            .Then(context =>
            {
                Console.WriteLine("Goodbye world");
                return ExecutionResult.Next();
            });
    }
}

工作流中的每个步骤都可以保存在数据库中,可以将工作流中的某个步骤在以后的执行。

配置

可以使用IServiceCollectionAddWorkflow扩展方法将服务进行注册。默认配置了MemoryPersistenceProviderSingleNodeConcurrencyProvider用于测试。同时开发者也可以配置数据库,用来实现工作流的持久化。

services.AddWorkflow();

工作流的使用

从容器中获取工作流服务,一定要调用RegisterWorkflow进行注册,然后调用start来启动工作流线程池,并使用StartWorkflow启动特定工作流。

var host = serviceProvider.GetService<IWorkflowHost>();            
host.RegisterWorkflow<HelloWorldWorkflow>();
host.Start();

host.StartWorkflow("HelloWorld", 1, null);

Console.ReadLine();
host.Stop();

步骤之间传递参数

//带有输入和输出参数的步骤
public class AddNumbers : StepBody
{
    public int Input1 { get; set; }

    public int Input2 { get; set; }

    public int Output { get; set; }

    public override ExecutionResult Run(IStepExecutionContext context)
    {
        Output = (Input1 + Input2);
        return ExecutionResult.Next();
    }
}

//定义内部数据类
public class MyDataClass
{
    public int Value1 { get; set; }
    public int Value2 { get; set; }
    public int Answer { get; set; }
}

//自定义类映射到步骤的输入和输出参数上
public class PassingDataWorkflow : IWorkflow<MyDataClass>
{  
    public void Build(IWorkflowBuilder<MyDataClass> builder)
    {
        builder            
            .StartWith<AddNumbers>()
                .Input(step => step.Input1, data => data.Value1)
                .Input(step => step.Input2, data => data.Value2)
                .Output(data => data.Answer, step => step.Output)
            .Then<CustomMessage>()
                .Input(step => step.Message, data => "The answer is " + data.Answer.ToString());
    }
    ...
}

步骤的依赖注入

如果使用IOC容器注入步骤,工作流则会使用容器来注入步骤的依赖项

需要注入依赖的服务:

public interface IMyService
{
    void DoTheThings();
}
...
public class MyService : IMyService
{
    public void DoTheThings()
    {
        Console.WriteLine("Doing stuff...");
    }
}
//在使用之前要将服务以瞬态方式加入到容器的服务集合中,考虑可能并发使用工作流,不要将服务注册为单例
IServiceCollection services = new ServiceCollection();
services.AddWorkflow();

services.AddTransient<DoSomething>();
services.AddTransient<IMyService, MyService>();


public class DoSomething : StepBody
{
    private IMyService _myService;

    public DoSomething(IMyService myService)
    {
        _myService = myService;
    }

    public override ExecutionResult Run(IStepExecutionContext context)
    {
        _myService.DoTheThings();
        return ExecutionResult.Next();
    }
}

案例1 基本使用

  • steps
public class GoodbyeWorld : StepBody
{

    private ILogger _logger;

    public GoodbyeWorld(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger<GoodbyeWorld>();
    }

    public override ExecutionResult Run(IStepExecutionContext context)
    {
        Console.WriteLine("Goodbye world");
        _logger.LogInformation("Hi there!");
        return ExecutionResult.Next();
    }
}

public class HelloWorld : StepBody
{
    public override ExecutionResult Run(IStepExecutionContext context)
    {
        Console.WriteLine("Hello world");
        return ExecutionResult.Next();
    }
}
  • workflow
public class HelloWorldWorkflow : IWorkflow
{
    public void Build(IWorkflowBuilder<object> builder)
    {
        builder                
            .UseDefaultErrorBehavior(WorkflowErrorHandling.Suspend)
            .StartWith<HelloWorld>()                
            .Then<GoodbyeWorld>();
    }

    public string Id => "HelloWorld";
        
    public int Version => 1;
             
}
  • program
IServiceCollection services = new ServiceCollection();
services.AddLogging();
services.AddWorkflow();
services.AddTransient<GoodbyeWorld>();//因为GloodbyeWorld中使用了依赖注入,所以需要向容器中进行注册
var serviceProvider = services.BuildServiceProvider();
var host = serviceProvider.GetService<IWorkflowHost>();
host.RegisterWorkflow<HelloWorldWorkflow>();        
host.Start();            
host.StartWorkflow("HelloWorld");
Console.ReadLine();
host.Stop();

案例2 传递数据

  • DataClass
public class MyDataClass
{
    public int Value1 { get; set; }
    public int Value2 { get; set; }
    public int Value3 { get; set; }
}
  • steps
public class AddNumbers : StepBodyAsync
{
    public int Input1 { get; set; }
    public int Input2 { get; set; }
    public int Output { get; set; }

    public override async Task<ExecutionResult> RunAsync(IStepExecutionContext context)
    {
        Output = (Input1 + Input2);
        return ExecutionResult.Next();
    }
}

public class CustomMessage : StepBody
{
    
    public string Message { get; set; }
    public override ExecutionResult Run(IStepExecutionContext context)
    {
        Console.WriteLine(Message);
        return ExecutionResult.Next();
    }
}

  • workflow
public class PassingDataWorkflow : IWorkflow<MyDataClass>
{  
    public void Build(IWorkflowBuilder<MyDataClass> builder)
    {
        builder
            .StartWith(context =>
            {
                Console.WriteLine("Starting workflow...");
                return ExecutionResult.Next();
            })
            .Then<AddNumbers>()
                .Input(step => step.Input1, data => data.Value1)//将Input1和data.Value1进行绑定
                .Input(step => step.Input2, data => data.Value2)
                .Output(data => data.Value3, step => step.Output)//将step.Output赋值给data.Value3
            .Then<CustomMessage>()
                .Name("Print custom message")
                .Input(step => step.Message, data => "The answer is " + data.Value3.ToString())
            .Then(context =>
                {
                    Console.WriteLine("Workflow complete");
                    return ExecutionResult.Next();
                });
    }
    public string Id => "PassingDataWorkflow";  
    public int Version => 1;
}


public class PassingDataWorkflow2 : IWorkflow<Dictionary<string, int>>
{
    public void Build(IWorkflowBuilder<Dictionary<string, int>> builder)
    {
        builder
            .StartWith(context =>
            {
                Console.WriteLine("Starting workflow...");
                return ExecutionResult.Next();
            })
            .Then<AddNumbers>()
                .Input(step => step.Input1, data => data["Value1"])
                .Input(step => step.Input2, data => data["Value2"])
                .Output((step, data) => data["Value3"] = step.Output)
            .Then<CustomMessage>()
                .Name("Print custom message")
                .Input(step => step.Message, data => "The answer is " + data["Value3"].ToString())
            .Then(context =>
                {
                    Console.WriteLine("Workflow complete");
                    return ExecutionResult.Next();
                });
    }

    public string Id => "PassingDataWorkflow2";

    public int Version => 1;

}

  • program
IServiceCollection services = new ServiceCollection();
services.AddLogging();
services.AddWorkflow();
var serviceProvider = services.BuildServiceProvider();
var host = serviceProvider.GetService<IWorkflowHost>();
host.RegisterWorkflow<PassingDataWorkflow, MyDataClass>();
host.RegisterWorkflow<PassingDataWorkflow2, Dictionary<string, int>>();
host.Start();
var initialData = new MyDataClass
{
    Value1 = 2,
    Value2 = 3
};
//使用PassingDataWorkflow
host.StartWorkflow("PassingDataWorkflow", 1, initialData);
var initialData2 = new Dictionary<string, int>
{
    ["Value1"] = 7,
    ["Value2"] = 2
};
//使用PassingDataWorkflow2
host.StartWorkflow("PassingDataWorkflow2", 1, initialData2);

Console.ReadLine();
host.Stop();
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值