using MessageFlow; namespace MessageFlow.Samples; /// /// The kind of a support ticket. /// public enum TicketKind { /// A refund request. Refund, /// A password reset request. PasswordReset, /// Anything the automated handlers do not understand. Other, } /// /// A support ticket flowing through the triage chain. /// /// The ticket identifier. /// The kind of the ticket. public sealed class Ticket(int id, TicketKind kind) { /// Gets the ticket identifier. public int Id { get; } = id; /// Gets the kind of the ticket. public TicketKind Kind { get; } = kind; } /// /// Handles refund tickets. /// public sealed class RefundHandler : HandlerBase { /// protected override bool CanHandle(Ticket request) { ArgumentNullException.ThrowIfNull(request); return request.Kind == TicketKind.Refund; } /// protected override ValueTask ProcessAsync(Ticket request, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(request); return new ValueTask($"refund issued for ticket {request.Id}"); } } /// /// Handles password reset tickets. /// public sealed class PasswordResetHandler : HandlerBase { /// protected override bool CanHandle(Ticket request) { ArgumentNullException.ThrowIfNull(request); return request.Kind == TicketKind.PasswordReset; } /// protected override ValueTask ProcessAsync(Ticket request, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(request); return new ValueTask($"reset link sent for ticket {request.Id}"); } } /// /// Routes support tickets to reusable implementations. /// public static class SupportTicketSample { /// /// Builds the ticket triage chain, escalating anything the handlers do not accept. /// /// The composed chain. public static IChain BuildChain() => Chain.Create() .Use(new RefundHandler()) .Use(new PasswordResetHandler()) .WithFallback((request, _) => new ValueTask($"escalated ticket {request.Id} to a human")) .Build(); /// /// Runs the sample against one ticket of every kind. /// /// The writer receiving the sample output. /// A token used to cancel the operation. /// The triage decisions, in ticket order. public static async Task> RunAsync( TextWriter output, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(output); var chain = BuildChain(); var tickets = new[] { new Ticket(1, TicketKind.Refund), new Ticket(2, TicketKind.PasswordReset), new Ticket(3, TicketKind.Other), }; var results = new List(); foreach (var ticket in tickets) { var response = await chain.ExecuteAsync(ticket, cancellationToken).ConfigureAwait(false); results.Add(response); await output.WriteLineAsync($"ticket {ticket.Id} ({ticket.Kind}) => {response}").ConfigureAwait(false); } return results; } }