工作流可以在工作流开始或者完成之前或者之后使用中间件进行扩展。
步骤中间件 步骤中间件可以为给定的步骤执行其他代码。
使用 创建实现了IWorkflowStepMiddleware
的中间件类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class LogCorrelationStepMiddleware : IWorkflowStepMiddleware { private readonly ILogger<LogCorrelationStepMiddleware> _log; public LogCorrelationStepMiddleware ( ILogger<LogCorrelationStepMiddleware> log ) { _log = log; } public async Task<ExecutionResult> HandleAsync ( IStepExecutionContext context, IStepBody body, WorkflowStepDelegate next ) { var workflowId = context.Workflow.Id; var stepId = context.Step.Id; using (_log.BeginScope("{@WorkflowId}" , workflowId)) using (_log.BeginScope("{@StepId}" , stepId)) { return await next(); } } }
前流程中间件 在工作流启动之前运行的中间件,可以更改工作流上的属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class AddDescriptionWorkflowMiddleware : IWorkflowMiddleware { public WorkflowMiddlewarePhase Phase => WorkflowMiddlewarePhase.PreWorkflow; public Task HandleAsync ( WorkflowInstance workflow, WorkflowDelegate next ) { if (workflow.Data is IDescriptiveWorkflowParams descriptiveParams) { workflow.Description = descriptiveParams.Description; } return next(); } } public interface IDescriptiveWorkflowParams { string Description { get ; } } public MyWorkflowParams : IDescriptiveWorkflowParams{ public string Description => $"Run task '{TaskName} '" ; public string TaskName { get ; set ; } }
前中间件的异常处理 前中间件和后中间件的异常处理方式不同,前中间件在工作流之前运行,所以前工作流中间件引发的异常会冒泡到StartWorkflow方法,并且由调用StartWorkflow的调用方法来捕获异常。
1 2 3 4 5 6 7 8 9 10 11 public async Task MyMethodThatStartsAWorkflow (){ try { await host.StartWorkflow("HelloWorld" , 1 , null ); } catch (Exception ex) { } }
后流程中间件 在工作流完成之后运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class PrintWorkflowSummaryMiddleware : IWorkflowMiddleware { private readonly ILogger<PrintWorkflowSummaryMiddleware> _log; public PrintWorkflowSummaryMiddleware ( ILogger<PrintWorkflowSummaryMiddleware> log ) { _log = log; } public WorkflowMiddlewarePhase Phase => WorkflowMiddlewarePhase.PostWorkflow; public Task HandleAsync ( WorkflowInstance workflow, WorkflowDelegate next ) { if (!workflow.CompleteTime.HasValue) { return next(); } var duration = workflow.CompleteTime.Value - workflow.CreateTime; _log.LogInformation($@"Workflow {workflow.Description} completed in {duration:g} " ); foreach (var step in workflow.ExecutionPointers) { var stepName = step.StepName; var stepDuration = (step.EndTime - step.StartTime) ?? TimeSpan.Zero; _log.LogInformation($" - Step {stepName} completed in {stepDuration:g} " ); } return next(); } }
后中间件的异常处理 在后中间件执行时,工作流已经完成。默认情况下,工作流中间件引发异常,会记录该异常,并且工作流会照常执行完成,但是可以设置更改。要更改工作流默认的后中间件错误处理,要在依赖关系注入框架中注册IWorkflowMiddlewareErrorHandler
。
1 2 3 4 5 6 7 8 9 10 11 public class CustomHandler : IWorkflowMiddlewareErrorHandler { public Task HandleAsync (Exception ex ) { } } services.AddWorkflow(); services.AddTransient<IWorkflowMiddlewareErrorHandler, CustomHandler>();
注册中间件 要想使用中间件,需将中间件注册到容器中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class Startup { public void ConfigureServices (IServiceCollection services ) { ... services.AddWorkflowMiddleware<AddDescriptionWorkflowMiddleware>(); services.AddWorkflowMiddleware<PrintWorkflowSummaryMiddleware>(); services.AddWorkflowStepMiddleware<LogCorrelationStepMiddleware>(); services.AddWorkflowStepMiddleware<PollyRetryMiddleware>(); ... } }
案例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Log1 : StepBodyAsync { public override Task<ExecutionResult> RunAsync (IStepExecutionContext context ) { Console.WriteLine("Log1:步骤执行" ); return Task.FromResult(ExecutionResult.Next()); } } public class Log2 : StepBodyAsync { public override Task<ExecutionResult> RunAsync (IStepExecutionContext context ) { Console.WriteLine("Log2:步骤执行" ); return Task.FromResult(ExecutionResult.Next()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 public class FlakyConnectionWorkflow : IWorkflow { public string Id => "flaky-sample" ; public int Version => 1 ; public void Build (IWorkflowBuilder<object > builder ) { builder .StartWith<Log1>() .Then<Log2>(); } }
middleware
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class pre : IWorkflowMiddleware { public WorkflowMiddlewarePhase Phase => WorkflowMiddlewarePhase.PreWorkflow; public Task HandleAsync (WorkflowInstance workflow, WorkflowDelegate next ) { System.Console.WriteLine("前流程中间件1" ); return next(); } } public class post : IWorkflowMiddleware { public WorkflowMiddlewarePhase Phase => WorkflowMiddlewarePhase.PostWorkflow; public Task HandleAsync (WorkflowInstance workflow, WorkflowDelegate next ) { Console.WriteLine("后中间件" ); return next(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 internal class stepM1 : IWorkflowStepMiddleware { public async Task<ExecutionResult> HandleAsync (IStepExecutionContext context, IStepBody body, WorkflowStepDelegate next ) { Console.WriteLine("步骤中间件1" ); return await next(); } } internal class stepM2 : IWorkflowStepMiddleware { public async Task<ExecutionResult> HandleAsync (IStepExecutionContext context, IStepBody body, WorkflowStepDelegate next ) { Console.WriteLine("步骤中间件2" ); return await next(); } }
program
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 IServiceCollection services = new ServiceCollection(); services.AddWorkflow(); services.AddWorkflowStepMiddleware<stepM1>(); services.AddWorkflowStepMiddleware<stepM2>(); services.AddWorkflowMiddleware<pre>(); services.AddWorkflowMiddleware<pre2>(); services.AddWorkflowMiddleware<post>(); services.AddLogging(); var serviceProvider = services.BuildServiceProvider();var host = serviceProvider.GetService<IWorkflowHost>();host.RegisterWorkflow<FlakyConnectionWorkflow>(); host.Start(); host.StartWorkflow("flaky-sample" ); Console.ReadLine();