Pular para o conteúdo
.NETNotifications e Pipeline Behaviors
Módulo 07Tópicos Avançados (Bônus)

Notifications e Pipeline Behaviors

avancado 40 min de leitura·Atualizado · .NET 9
Resumo

Notifications (publish/subscribe) permitem que múltiplos handlers reajam a um evento. Pipeline Behaviors envolvem o processamento de mensagens — ideais para validação transversal com FluentValidation.

1. Objetivos de Aprendizagem#

  • Publicar notifications para múltiplos handlers.
  • Criar um Pipeline Behavior de validação.
  • Integrar FluentValidation ao pipeline do MediatR.

2. Pré-requisitos#

  • Requests e commands com MediatR (tópico 44.3).

3. Conceito#

  • Notification (INotification): um evento publicado com IPublisher.Publish; N handlers podem reagir (ex.: "produto criado" → enviar e-mail + invalidar cache).
  • Pipeline Behavior (IPipelineBehavior): um wrapper em torno de todos os handlers — como um middleware para mensagens. O porquê: aplicar validação, logging e transações num único lugar, sem repetir em cada handler.

O Pipeline Behavior envolve o handler, como um middleware para mensagens:

Carregando diagrama…

Uma Notification faz fan-out para múltiplos handlers independentes:

Carregando diagrama…

4. Mão na Massa#

4.1. Setup#

Shell
dotnet add Catalog.Application package FluentValidation
dotnet add Catalog.Application package FluentValidation.DependencyInjectionExtensions

Registro:

C#
builder.Services.AddValidatorsFromAssembly(typeof(AssemblyMarker).Assembly);
builder.Services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(typeof(AssemblyMarker).Assembly);
    cfg.AddOpenBehavior(typeof(ValidationBehavior<,>));
});

4.2. Implementação Passo a Passo#

  1. Notification + handlers:
C#
public record ProdutoCriadoNotification(Guid Id, string Nome) : INotification;

internal sealed class EnviarEmailHandler : INotificationHandler<ProdutoCriadoNotification>
{
    public Task Handle(ProdutoCriadoNotification n, CancellationToken ct)
    {
        // enviar e-mail (simplificado)
        return Task.CompletedTask;
    }
}

internal sealed class InvalidarCacheHandler : INotificationHandler<ProdutoCriadoNotification>
{
    public Task Handle(ProdutoCriadoNotification n, CancellationToken ct)
    {
        // invalidar cache
        return Task.CompletedTask;
    }
}

Publicando no command handler: await _publisher.Publish(new ProdutoCriadoNotification(id, nome), ct);

  1. Validador FluentValidation:
C#
public class CreateProdutoValidator : AbstractValidator<CreateProdutoCommand>
{
    public CreateProdutoValidator()
    {
        RuleFor(x => x.Produto.Nome).NotEmpty().MaximumLength(60);
        RuleFor(x => x.Produto.Preco).GreaterThan(0);
    }
}
  1. Behavior de validação:
C#
public sealed class ValidationBehavior<TRequest, TResponse>
    : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;
    public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
        => _validators = validators;

    public async Task<TResponse> Handle(TRequest request,
        RequestHandlerDelegate<TResponse> next, CancellationToken ct)
    {
        if (_validators.Any())
        {
            var context = new ValidationContext<TRequest>(request);
            var failures = _validators
                .Select(v => v.Validate(context))
                .SelectMany(r => r.Errors)
                .Where(f => f is not null)
                .ToList();

            if (failures.Count != 0)
                throw new ValidationException(failures);
        }
        return await next();
    }
}

4.3. Executando#

Enviar um CreateProdutoCommand inválido dispara ValidationException no behavior, antes do handler — capturada pelo handler global (Módulo 19) como 422.

5. Exemplo Completo#

Fluxo: Send(command)ValidationBehavior valida → handler executa e Publish(notification) → múltiplos handlers reagem em paralelo.

6. Boas Práticas e Armadilhas#

FaçaEvite
Centralizar validação num behaviorRepetir validação em cada handler
Notifications para efeitos colaterais desacopladosAcoplar e-mail/cache dentro do command handler
Mapear ValidationException no handler globalDeixar a exceção virar 500
Atenção

handlers de notification não devem lançar exceções que quebrem o fluxo principal se forem apenas efeitos colaterais. Considere isolá-los (try/catch, fila) para que uma falha de e-mail não derrube a criação do produto.

7. Segurança e Produção#

  • Um behavior é o lugar ideal para autorização por caso de uso e logging/auditoria centralizados.
  • Efeitos colaterais críticos devem ser resilientes (retry, outbox) em produção.

8. Exercícios#

  • Fácil: adicione um LoggingBehavior que loga cada request.
  • Médio: valide o UpdateProdutoCommand com FluentValidation.
  • Desafio: implemente um padrão outbox para publicar notifications de forma confiável.

9. Resumo#

Notifications propagam eventos a múltiplos handlers; Pipeline Behaviors envolvem o processamento para aplicar validação (FluentValidation), logging e autorização de forma transversal, mantendo os handlers focados.

10. Próximos Passos#

Você concluiu o curso. Revise os módulos de segurança (05, 25, 26, 27, 28) antes de publicar uma API em produção.

11. Referências#

44-04 — Notifications e Pipeline Behaviors | Curso ASP.NET Core