Skip to content

Cookbook and Scenarios

A. Shafie edited this page Sep 26, 2025 · 1 revision

Cookbook and Scenarios

This page provides practical, recipe-style solutions for common scenarios you might encounter when building applications with LiteBus.

Recipe: Contextual Scenario Handling

Problem: You need to process the same command differently based on where the request came from. For example, a command from a public API needs stricter validation than one from an internal admin tool.

Solution: Use handler tags to create context-specific pipelines.

1. Define Your Contexts

Create a static class to hold your context tags. This avoids magic strings.

public static class RequestContexts
{
    public const string PublicApi = "PublicAPI";
    public const string AdminPortal = "AdminPortal";
}

2. Tag Your Handlers

Apply the [HandlerTag] attribute to handlers that should only run in a specific context.

// This validator only runs for requests from the public API.
[HandlerTag(RequestContexts.PublicApi)]
public class StrictUserUpdateValidator : ICommandValidator<UpdateUserCommand>
{
    public Task ValidateAsync(UpdateUserCommand command, CancellationToken cancellationToken)
    {
        // Public API cannot change a user's role.
        if (command.Role != null)
        {
            throw new ValidationException("Role cannot be changed via the public API.");
        }
        return Task.CompletedTask;
    }
}

// This handler is untagged, so it runs for ALL contexts.
public class CommonUserUpdateValidator : ICommandValidator<UpdateUserCommand>
{
    public Task ValidateAsync(UpdateUserCommand command, CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(command.Email))
        {
            throw new ValidationException("Email is required.");
        }
        return Task.CompletedTask;
    }
}

3. Mediate with Context

When sending the command, specify the context tag.

// In your Public API controller:
[HttpPut("{id}")]
public async Task<IActionResult> UpdateUser(Guid id, UpdateUserCommand command)
{
    // Send the command with the "PublicAPI" context.
    // This will trigger both the StrictUserUpdateValidator and the CommonUserUpdateValidator.
    await _commandMediator.SendAsync(command, RequestContexts.PublicApi);
    return NoContent();
}

// In your Admin Portal controller:
[HttpPut("{id}")]
public async Task<IActionResult> UpdateUserFromAdmin(Guid id, UpdateUserCommand command)
{
    // Send the command with the "AdminPortal" context.
    // This will ONLY trigger the CommonUserUpdateValidator, as the strict validator is not tagged for this context.
    await _commandMediator.SendAsync(command, RequestContexts.AdminPortal);
    return NoContent();
}

Result: You have successfully implemented different validation rules for the same command without if/else logic in your handlers, keeping them clean and focused.


(More recipes can be added here over time, such as "Implementing a Saga," "Cross-cutting Caching," etc.)

Clone this wiki locally