Open source

PMQ.Mediator

nível aplicado-em-producao

713 downloads · repositório

Mediator para .NET com pipeline de comportamento, integração de validação, streaming e publicação de notificação. 37 arquivos, 2.154 linhas.

O problema

Num serviço com muitos casos de uso, o controller vira despachante: injeta cinco dependências, valida, chama serviço, trata erro. O mediator tira isso do caminho: o controller entrega um comando e recebe um resultado, e tudo que acontece no meio é composição.

A decisão que amarra a suíte

Validação, log e transação não são responsabilidade do handler: são estágios que envolvem qualquer handler. O que torna esse pipeline diferente é o que ele faz quando a validação falha:

// Try to use the custom failure handler if registered
var failureHandler = serviceProvider.GetService<IValidationFailureHandler<TResponse>>();

if (failureHandler is not null)
    return failureHandler.HandleFailure(failures);

// If no custom handler, throw a ValidationException
throw new ValidationException(failures);

Se existe um tratador registrado, a falha de validação vira valor de retorno; se não existe, cai para exceção. É o ponto onde o PMQ.Notifications se encaixa: quem adota a suíte inteira registra o tratador e a regra violada nunca vira exceção; quem usa só o mediator continua com o comportamento idiomático do .NET.

Foi assim que a fraqueza aceita no PMQ.Notifications, em que nada obriga o chamador a verificar, acabou resolvida estruturalmente. O pipeline verifica por todo mundo, antes de o handler existir.

Outras decisões

Validador resolvido por requisição, não no arranque. Se não há validador registrado para aquele comando, o pipeline segue direto. Custa uma consulta ao contêiner e evita obrigar todo comando a ter validador só para o pipeline não quebrar.

Validadores rodam em paralelo com Task.WhenAll, e os erros são concatenados. Serial devolveria o primeiro conjunto de erros; paralelo devolve todos, que é a mesma razão de ser da suíte.

Streaming como abstração separada, com IStreamRequest e IStreamPipelineBehavior, porque resposta única e sequência têm ciclo de vida diferente, e forçar as duas na mesma interface produz um tipo que mente sobre metade dos casos.

Origem

Escrevi um mediator antes deste, para desacoplar módulos de um serviço corporativo, e ele funcionou. Este aqui é o que eu faria sabendo o que aquele me ensinou: mesma ideia, implementação melhor.

Pablo Mickael Quevedo Senior Software Engineer · Novo Hamburgo, RS