No C# uma classe pode definir comportamentos a serem disparados quando determinada ação acontece. Esses comportamentos podem ser assinados para que quando ocorram alguém seja notificado.
Eventos ocorrem de forma assíncrona não interrompendo o fluxo normal de seu código dando mais flexibilidade distribuindo-as melhor quando não existe a necessidade de esperar que um processo seja finalizado.
Podemos tomar como um exemplo para este caso o cadastro de um usuário em um sistema: ao cadastrar o usuário podemos criar um evento para notificar a criação do usuário e neste fazer o envio de um e-mail de boas vindas.
Não precisamos esperar o envio do e-mail para que o cadastro seja finalizado. Neste caso o envio do e-mail é um processo secundário que pode ser implementado através do um evento de domínio.
No TNF encontramos suporte ao um pattern chamado Domain Event.
Para usar a estrutura de Domain Events instale o pacote Tnf via nuget disponível em: https://www.myget.org/F/tnf/api/v3/index.json
EventBus é um objeto registrado como singleton no TNF que é compartilhado na aplicação para que seja usado para manipular e controlar os eventos.
Abaixo tomamos como exemplo a criação de um evento para o registro da entidade Person.
using Castle.Core.Logging; using Tnf.Architecture.Domain.Interfaces.Services; using Tnf.Dependency; using Tnf.Events.Bus; using Tnf.Events.Bus.Handlers; namespace Tnf.Architecture.Domain.Events { public class NewRegistrationHandler : IEventHandler<NewRegistrationEventData>, ITransientDependency { private readonly ILogger _logger; public NewRegistrationHandler(ILogger logger) => _logger = logger; public void HandleEvent(NewRegistrationEventData eventData) { _logger.Info("Registration event triggered"); } } public class NewRegistrationEventData : EventData { public PersonDto Person { get; } public NewRegistrationEventData(PersonDto person) { Person = person; } } }
A primeira classe chamada NewRegistrationHandler contém a implementação do comportamento do evento. Toda vez que o evento for disparado essa classe será chamada. Desta forma observe que a interface ITransientDependency (injeção de dependência através de convenções) está presente por este motivo. Esse evento é transitório e será criado para cada cadastro criado no sistema.
Perceba que também implementamos o nosso EventData, onde definimos a estrutura de dados do evento disparado.
Na classe abaixo o evento é disparado dentro do serviço de domínio onde é feita a injeção da interface IEventBus:
using Tnf.Architecture.Domain.Events; using Tnf.Architecture.Domain.Interfaces.Services; using Tnf.App.Domain.Services; using Tnf.Dto; using Tnf.Events.Bus; namespace Tnf.Architecture.Domain.Registration { public class RegistrationService : AppDomainService<IPersonRepository>, IRegistrationService { private readonly IEventBus _eventBus; public RegistrationService(IPersonRepository repository, IEventBus eventBus) : base(repository) { _eventBus = eventBus; } public PersonDto Register(PersonDto dto) { var builder = new PersonBuilder() .WithName(dto.Name); var person = builder.Build(); if (!Notification.HasNotification()) { var id = Repository.CreatePerson(person); dto.Id = id; } // Trigger event before create person _eventBus.Trigger(new NewRegistrationEventData(dto)); return dto; } } }
Observe que após o objeto de domínio ser construído e estar valido, o repositório é consumido cadastrando um novo dado, fazendo o disparo do evento através da interface IEventBus injetada em nosso serviço de domínio.
O método Trigger da interface IEventBus recebe o dado do evento representando a sua estrutura.
Nesse momento o Handler implementado anteriormente será chamado e executado.