Bolt.RequestBus : Publish and Handle Events – Part 3

This is third part of the series. In our previous post we discuss about how to add validation for a request. If you don’t know what Bolt.RequestBus is please read the post. In this part I am trying to show how you publish and handle events.

Lets take registration as an example and here are the requirements.

1. User can register using email and password
2. After successful registration user should receive an email
3. After successful registration user should logged in the system

If you check the requirements registration is the main functionality or simply creating the user in the database is what registration required. Sending email and automatically logged the user in is side effect of a successful registration and they are good candidate to handle in an event. Lets see how.

First define the command and event dto.

public class RegisterUserRequest : IRequest
{
    public string Email { get; set; }
    public string Password { get; set; }
}

public class UserRegisteredEvent : IEvent
{
    public string Id { get; set; }
    public string Email { get; set; }
}

From the controller send this command

public class AccountController : Controller
{
    private readonly IRequestBus bus;

    public AccountController(IRequestBus bus)
    {
        this.bus = bus;
    }

    public async Task<ActionResult> Register(RegisterUserRequest request)
    {
        var response = await bus.SendAsync(request);

        return this.ResponseResult(response,
            () => Redirect(Url.Home()),
            () => View(request));
    }
}

Define a handler to handle RegisterUserRequest.

public class RegisterUserRequestHandler : AsyncRequestHandlerBase<RegisterUserRequest>
{
    private readonly IUserRepository repo;
    private readonly IMapper mapper;
    private readonly IRequestBus bus;

    public RegisterUserRequestHandler(IUserRepository repo, IMapper mapper, IRequestBus bus)
    {
        this.repo = repo;
        this.mapper = mapper;
        this.bus = bus;
    }

    protected override async Task ProcessAsync(RegisterUserRequest request)
    {
        var record = mapper.Map<RegisterUserRequest, UserRecord>(request);
        record.Id = Guid.NewGuid();

        await repo.CreateUserAsync(record);

        await bus.PublishAsync(new UserRegisteredEvent
        {
            Id = record.Id,
            Email = record.Email
        });
    }
}

Up to this level we make sure user can register in system. But now we need to finish other two requirements. One send welcome to registered user and logged the user in. Lets define two event handlers to finish those two requirements.

public class SendEmailToUserOnUserRegisteredHandler : IAsyncEventHandler<UserRegisteredEvent>
{
    private readonly IEmailSender sender;

    public SendEmailToUserOnUserRegistered(IEmailSender sender)
    {
        this.sender = sender;
    }

    public async Task HandleAsync(UserRegisteredEvent eEvent)
    {
        await sender.SendWelcomeEmailAsync();
    }
}

public class LoggedUserInOnUserRegisteredHandler : IAsyncEventHandler<UserRegisteredEvent>
{
    private readonly IAuth auth;

    public LoggedUserInOnUserRegistered(IAuth auth)
    {
        this.auth = auth;
    }

    public Task HandleAsync(UserRegisteredEvent eEvent)
    {
        auth.Authenticate(eEvent.Id);

        return Task.FromResult(0);
    }
}

All the events should pick by ioc as we setup ioc as below based on previous post’s example. Thant means anything ends with name “Handler” should automatically registered:

builder.RegisterAssemblyTypes(assemblies)
            .Where(a => a.IsClass && 
                    (a.Name.EndsWith("Handler")                
                    || a.Name.EndsWith("Validator"))
            )
            .AsImplementedInterfaces();

Hopefully this example make it clear how we can publish event and handle event. This also showing how powerful event based system is, as it allows loos coupling between functionalities and help you to mkae requesthandler follow S of SOLID principle. RequestHandler can do only one thing and should change for only one reason and same applies to all event handlers.

Note: Regarding sending email, in real system where scaling and performance is important you most likely don’t want to send them from your application but push event to some queue and let the email sent by a service that listening the queue for this specific event.

That’s all for today. Happy coding 🙂

Advertisements

4 thoughts on “Bolt.RequestBus : Publish and Handle Events – Part 3

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s