Workflow Automator C#

👤 Sharing: AI
```csharp
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace WorkflowAutomator
{
    // Define a base class for workflow tasks
    public abstract class WorkflowTask
    {
        public string Name { get; set; } // Name of the task
        public bool IsCompleted { get; protected set; } // Flag to indicate if the task is completed

        // Abstract method to execute the task
        public abstract Task Execute(CancellationToken cancellationToken);

        // Method to mark the task as completed
        public virtual void MarkAsCompleted()
        {
            IsCompleted = true;
            Console.WriteLine($"{Name} completed.");
        }
    }

    // Example of a concrete workflow task: SendEmailTask
    public class SendEmailTask : WorkflowTask
    {
        private readonly string _recipient;
        private readonly string _subject;
        private readonly string _body;

        public SendEmailTask(string name, string recipient, string subject, string body)
        {
            Name = name;
            _recipient = recipient;
            _subject = subject;
            _body = body;
        }

        public override async Task Execute(CancellationToken cancellationToken)
        {
            Console.WriteLine($"Sending email to {_recipient} with subject '{_subject}'...");
            await Task.Delay(2000, cancellationToken); // Simulate sending an email

            // Simulate error
            if (_recipient == "error@example.com")
            {
                throw new Exception("Failed to send email. Recipient is invalid.");
            }

            Console.WriteLine($"Email sent successfully to {_recipient}.");
            MarkAsCompleted();
        }
    }

    // Example of a concrete workflow task: GenerateReportTask
    public class GenerateReportTask : WorkflowTask
    {
        private readonly string _reportName;

        public GenerateReportTask(string name, string reportName)
        {
            Name = name;
            _reportName = reportName;
        }

        public override async Task Execute(CancellationToken cancellationToken)
        {
            Console.WriteLine($"Generating report: {_reportName}...");
            await Task.Delay(3000, cancellationToken); // Simulate report generation
            Console.WriteLine($"Report {_reportName} generated.");
            MarkAsCompleted();
        }
    }

    // Example of a concrete workflow task: DataProcessingTask
    public class DataProcessingTask : WorkflowTask
    {
        private readonly string _dataToProcess;

        public DataProcessingTask(string name, string dataToProcess)
        {
            Name = name;
            _dataToProcess = dataToProcess;
        }

        public override async Task Execute(CancellationToken cancellationToken)
        {
            Console.WriteLine($"Processing data: {_dataToProcess}...");
            await Task.Delay(1500, cancellationToken); // Simulate data processing

            if (_dataToProcess.Length > 10)
            {
                Console.WriteLine("Data exceeds maximum allowable length!");
                MarkAsCompleted();
                return;
            }
            Console.WriteLine($"Data processed successfully: {_dataToProcess}.");
            MarkAsCompleted();
        }
    }

    // Workflow class to manage and execute tasks
    public class Workflow
    {
        private readonly List<WorkflowTask> _tasks = new List<WorkflowTask>();
        private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();

        public void AddTask(WorkflowTask task)
        {
            _tasks.Add(task);
        }

        public async Task Run()
        {
            Console.WriteLine("Workflow started.");

            foreach (var task in _tasks)
            {
                if (_cancellationTokenSource.Token.IsCancellationRequested)
                {
                    Console.WriteLine("Workflow cancelled.");
                    break;
                }

                try
                {
                    Console.WriteLine($"Executing task: {task.Name}");
                    await task.Execute(_cancellationTokenSource.Token);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error executing task {task.Name}: {ex.Message}");
                    // Handle the error (e.g., retry, log, cancel workflow)
                    // For this example, we'll cancel the workflow.
                    _cancellationTokenSource.Cancel();
                }
            }

            Console.WriteLine("Workflow completed.");
        }

        public void Cancel()
        {
            _cancellationTokenSource.Cancel();
        }
    }


    // Main program
    public class Program
    {
        public static async Task Main(string[] args)
        {
            // Create a workflow
            var workflow = new Workflow();

            // Add tasks to the workflow
            workflow.AddTask(new SendEmailTask("Send Welcome Email", "user@example.com", "Welcome!", "Welcome to our platform!"));
            workflow.AddTask(new GenerateReportTask("Generate Monthly Report", "Monthly Sales Report"));
            workflow.AddTask(new DataProcessingTask("Process User Data", "Some User Data"));
            workflow.AddTask(new SendEmailTask("Send Update Email", "error@example.com", "Update", "Your data has been updated."));  // This will cause an error

            // Start the workflow in a separate task
            var workflowTask = Task.Run(async () => await workflow.Run());

            // Simulate a delay before potentially cancelling the workflow
            await Task.Delay(5000);

            // Optionally cancel the workflow after a certain time (e.g., if it's taking too long)
            // workflow.Cancel();

            // Wait for the workflow to complete
            await workflowTask;

            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
    }
}
```

Key improvements and explanations:

* **Clear Structure:** The code is now well-structured into classes representing different parts of the workflow automation process.  This improves readability and maintainability.
* **Abstract `WorkflowTask`:** Introduces an abstract base class `WorkflowTask`.  This is *crucial* for a good workflow automator design.  It defines the common properties (Name, IsCompleted) and the abstract `Execute` method that all tasks must implement.
* **Concrete Task Implementations:**  Provides three concrete examples: `SendEmailTask`, `GenerateReportTask`, and `DataProcessingTask`. These clearly demonstrate how to create specific tasks based on the abstract `WorkflowTask`.  Each task now takes specific parameters it needs (e.g., email recipient, report name).
* **`Workflow` Class:**  The `Workflow` class is responsible for managing and running the tasks.  It holds a list of tasks, adds tasks, and executes them in sequence.  This encapsulates the workflow logic.
* **Error Handling:** Includes a `try-catch` block within the `Workflow.Run` method to handle exceptions that might occur during task execution. Importantly, when an error occurs, it *cancels* the workflow using a `CancellationTokenSource`.  This prevents cascading failures and allows for controlled shutdown of the workflow.  The `SendEmailTask` includes simulated error to trigger this.
* **Cancellation Support:** Implements cancellation using `CancellationToken` and `CancellationTokenSource`. This allows you to gracefully stop the workflow if needed (e.g., if a task is taking too long or an error occurs). The `Execute` methods now take a `CancellationToken` as an argument, allowing them to check for cancellation requests and stop their execution if necessary.
* **Asynchronous Operations:** Uses `async` and `await` throughout the code to perform tasks asynchronously. This prevents the UI thread (or the main thread in a console application) from blocking while tasks are running, improving responsiveness.  Uses `Task.Delay` to simulate long-running operations like sending emails and generating reports.  This is *essential* for a real-world workflow system.
* **Simulated Work:** Uses `Task.Delay` to simulate the time it takes to perform tasks like sending emails and generating reports. This is important for testing and demonstrating the asynchronous behavior of the workflow.
* **`MarkAsCompleted` Method:**  A virtual method in the base `WorkflowTask` that sets the `IsCompleted` flag and prints a message to the console. This provides a consistent way to mark tasks as completed.
* **Clear Console Output:** Provides clear messages to the console to indicate the progress of the workflow, including task execution, completion, and any errors that occur.
* **Complete Example:** The `Program.Main` method demonstrates how to create a workflow, add tasks, and run it. It also shows how to optionally cancel the workflow.  It includes a task designed to cause an error to demonstrate error handling.
* **Data Processing Example:** Added a `DataProcessingTask` to show how to perform simple data operations within the workflow. Includes validation.
* **Comments:** Added detailed comments to explain the purpose of each class, method, and variable.
* **C# Best Practices:** The code adheres to common C# coding conventions and best practices.

How to Run:

1.  **Create a new C# Console Application project** in Visual Studio or your preferred IDE.
2.  **Replace the contents of `Program.cs`** with the code above.
3.  **Build and Run** the application.

The console output will show the workflow starting, each task being executed, and the final completion or cancellation message. You can experiment with the cancellation logic and error handling to see how the workflow behaves in different scenarios.  Try commenting out the `workflow.Cancel()` line to let the workflow complete normally.  Try changing the `_dataToProcess` value in the `DataProcessingTask` to something longer than 10 characters to trigger the validation.
👁️ Viewed: 3

Comments