using System; using System.Collections.Generic; namespace ECMJobRunner.Application.Common.Exceptions { /// /// Base exception class for job execution failures /// Provides a flexible structure for capturing job context and detailed error information /// /// /// Initializes a new instance of JobException with detailed context information /// /// Identifier of the profile associated with the job /// Name of the job that failed (e.g., "SQL Main Query", "ReC Request") /// Name of the process/stage being executed (e.g., "MainQueryExecution", "CheckQueryValidation") /// Unique batch identifier for tracking the execution /// Human-readable reason for the failure (nullable) /// The underlying exception that caused the failure (nullable) /// Additional contextual details as name-value pairs with optional null-handling /// /// The details parameter accepts tuples with: /// - Name: Display name of the detail /// - Value: String value of the detail (nullable) /// - IgnoreIfNull: If true, the detail is omitted from the message when value is null /// public class JobException(long profileId, string jobName, string processName, string batchId, string? reason, Exception? innerException, params (string Name, string? Value, bool IgnoreIfNull)[] details) : Exception( CreateMessage(jobName, [ ("Profile Id", profileId.ToString(), false), ("Job Name", jobName, false), ("Process Name", processName, false), ("Batch Id", batchId, false), ("Reason", reason, true), ..details ]), innerException) { /// /// Gets the profile identifier associated with the job execution /// public long ProfileId { get; } = profileId; /// /// Gets the name of the job that failed /// public string JobName { get; } = jobName; /// /// Gets the name of the process/stage that was being executed when the failure occurred /// public string ProcessName { get; } = processName; /// /// Gets the unique batch identifier for tracking the execution /// public string BatchId { get; } = batchId; /// /// Generates a formatted error message with job context and details /// /// Name of the job that failed /// Collection of name-value pairs with optional null-handling /// Formatted multi-line error message with visual separators /// /// Message format: /// /// {jobName} could not be completed. /// Process Name: {processName} /// Batch Id: {batchId} /// {additional details...} /// /// Details with IgnoreIfNull=true are omitted when their value is null. /// internal static string CreateMessage(string jobName, IEnumerable<(string Name, string? Value, bool IgnoreIfNull)> details) { var message = new System.Text.StringBuilder(); message.AppendLine($"{jobName} could not be completed."); foreach (var (name, value, ignoreNullValue) in details) { if (ignoreNullValue && value is null) continue; message.AppendLine($" {name}: {value}"); } return message.ToString(); } } }