After covering Dapr workflow basics in the previous article, let’s take a look at the different application patterns that can be used with Dapr workflow and .NET. The patterns covered in this post are: chaining, fan-out/fan-in, monitor, and external system interaction. Knowing which workflow patterns are available and when to use them is essential for using any workflow engine properly. Dapr workflows are stateful due to the underlying event-sourcing implementation. Workflows need to be written in a deterministic way because the workflow will replay several times during the execution. Some familiar programming constructs such as while loops, waiting/sleeping, and running parallel tasks are therefore required to be written in a workflow-friendly way, which this post covers in detail. Prerequisites All code samples shown in this post are taken from the dapr-workflow-demos GitHub repo. You can fork/clone the repository and run all the workflow samples locally. The following is required to run the samples: .NET 7 SDK Docker Desktop Dapr CLI (v1.11 or higher) A REST client, such as cURL, or the VSCode REST client extension. For simplicity, all workflow samples are using the same workflow activity, named CreateGreetingActivity. This activity will return a random greeting from an array of greetings and combines it with the input. Chaining pattern The purpose of the chaining pattern is to enforce a specific order of activity executions. The output of an activity is usually required as an input for the next activity. Or there is a strict sequence of interactions with external systems that are called from the activities. A real-life use case where chaining is essential is an order process. First, the inventory is checked, then the payment starts, and finally, the shipping is initiated. ChainingWorkflow sample The ChainingWorkflow sample in the GitHub repo contains a sequence of three activity calls. In this workflow, a random greeting will be added to the input string. Each time the CreateGreetingActivity is called, the output of the activity is used as the input for the next activity. Source code using Dapr.Workflow; namespace BasicWorkflowSamples{ public class ChainingWorkflow : Workflow<string, string> { public override async Task<string> RunAsync(WorkflowContext context, string input) { var message1 = await context.CallActivityAsync<string>( nameof(CreateGreetingActivity), input); var message2 = await context.CallActivityAsync<string>( nameof(CreateGreetingActivity), message1); var message3