dotnet add package CQRS.PostOffice
services.AddPostOffice();
public record HelloRequest(string Name) : IMail<string>;
public class HelloHandler : DeliveryAsync<HelloRequest, string>
{
public override Task<string> HandleAsync(HelloRequest request)
{
return Task.FromResult($"Hello, {request.Name}!");
}
}
var poster = services.GetRequiredService<Poster>();
var result = await poster.Send(new HelloRequest("World"));
Validators are automatically discovered and registered. Create validators that inherit from AbstractValidator<T>
:
services.AddPostOffice()
.AddValidation();
public class CreateUserRequestValidator : AbstractValidator<CreateUserRequest>
{
public CreateUserRequestValidator()
{
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Email).EmailAddress();
RuleFor(x => x.Age).GreaterThan(0).LessThan(150);
}
}
try
{
var result = await poster.Send(new CreateUserRequest("John", "[email protected]", 25));
}
catch (ValidationException ex)
{
foreach (var error in ex.Errors)
{
Console.WriteLine($"- {error.ErrorMessage}");
}
}
public class ErrorOrValidationBehavior<TMail, TResponse> : IPostageMiddleware<TMail, TResponse>
where TMail : IMail<TResponse>
where TResponse : IErrorOr
{
private readonly IValidator<TMail>? _validator;
public ErrorOrValidationBehavior(IValidator<TMail>? validator = null)
{
_validator = validator;
}
public async Task<(bool handled, TResponse? result)> StampAsync(TMail mail, Func<TMail, Task<TResponse>> next)
{
if (_validator is null)
{
return (false, default(TResponse));
}
ValidationResult validatorResult = await _validator.ValidateAsync(mail);
if (validatorResult.IsValid)
{
return (false, default(TResponse));
}
List<Error> errors = validatorResult.Errors.Select(x => Error.Validation(x.PropertyName, x.ErrorMessage)).ToList();
return (true, (TResponse)(dynamic)errors);
}
}
services.AddPostOffice();
services.AddTransient(typeof(IPostageMiddleware<,>), typeof(ErrorOrValidationBehavior<,>));
public record CreateUserCommand(string Name, string Email) : IMail<ErrorOr<string>>;
var result = await poster.Send(new CreateUserCommand("", "invalid-email"));
if (result.IsError)
{
foreach (var error in result.Errors)
{
Console.WriteLine($"- {error.Description}");
}
}
services.AddPostOffice()
.AddMiddleware<LoggingMiddleware<,>>()
.AddMiddleware<CachingMiddleware<,>>();
public class LoggingMiddleware<TMail, TResponse> : IPostageMiddleware<TMail, TResponse>
{
private readonly ILogger<LoggingMiddleware<TMail, TResponse>> _logger;
public LoggingMiddleware(ILogger<LoggingMiddleware<TMail, TResponse>> logger)
{
_logger = logger;
}
public async Task<(bool handled, TResponse? result)> StampAsync(
TMail mail, Func<TMail, Task<TResponse>> next)
{
_logger.LogInformation("Processing {MailType}", typeof(TMail).Name);
var stopwatch = Stopwatch.StartNew();
var result = await next(mail);
stopwatch.Stop();
_logger.LogInformation("Processed {MailType} in {ElapsedMs}ms",
typeof(TMail).Name, stopwatch.ElapsedMilliseconds);
return (false, result);
}
}
MIT License