namespace e_suite.Workflow.Core; //copied from Database.core. public class TaskDefinition { public string Type { get; set; } = string.Empty; public int Order { get; set; } public Dictionary? Config { get; set; } } public static class TaskExtensions { public static TaskDefinition ToDefinition(this ITask task, int order) { if (task is ITemplateValidatable v) { var errors = v.ValidateForTemplate().ToList(); if (errors.Any()) throw new InvalidOperationException( $"Task {task.GetType().Name} is invalid: {string.Join("; ", errors)}"); } return new TaskDefinition { Type = task.GetType().AssemblyQualifiedName!, Order = order, Config = ExtractConfig(task) }; } private static Dictionary ExtractConfig(object task) { var dict = new Dictionary(); foreach (var prop in task.GetType().GetProperties()) { if (!prop.CanRead) continue; if (prop.GetIndexParameters().Length > 0) continue; // skip indexers if (prop.IsDefined(typeof(RuntimeOnlyAttribute), inherit: true)) continue; var value = prop.GetValue(task); if (value != null) dict[prop.Name] = value; } return dict; } public static ITask ToTask(this TaskDefinition def) { var type = Type.GetType(def.Type, throwOnError: true)!; var task = (ITask)Activator.CreateInstance(type)!; foreach (var kvp in def.Config) { var prop = type.GetProperty(kvp.Key); if (prop == null || !prop.CanWrite) continue; if (prop.IsDefined(typeof(RuntimeOnlyAttribute), inherit: true)) continue; object? converted = ConvertValue(kvp.Value, prop.PropertyType); prop.SetValue(task, converted); } if (task is ITemplateValidatable v) { var errors = v.ValidateForTemplate().ToList(); if (errors.Any()) throw new InvalidOperationException( $"Task {task.GetType().Name} is invalid: {string.Join("; ", errors)}"); } return task; } private static object? ConvertValue(object? value, Type targetType) { if (value == null) return null; // Handle enums if (targetType.IsEnum) return Enum.Parse(targetType, value.ToString()!); // Handle Guid if (targetType == typeof(Guid)) return Guid.Parse(value.ToString()!); // Handle nullable types var underlying = Nullable.GetUnderlyingType(targetType); if (underlying != null) return Convert.ChangeType(value, underlying); return Convert.ChangeType(value, targetType); } public static bool IsCompleted(this ITask task) { return task.TaskState.In(TaskState.Completed, TaskState.Cancelled); } public static bool ReadyToActivate(this ITask task) { foreach (var predecessor in task.Predecessors) { if (!predecessor.IsCompleted()) { return false; } } return true; } }