Becoming a software developer – episode XIII

Datetime:2017-04-20 05:23:39         Topic: Coder  Assembler          Share        Original >>
Here to See The Original Article!!!

Welcome to the thirteenth episode of mycourse “Becoming a software developer” in which we will make use of the Command Handler pattern in order to extend our business logic and clean up the controllers.

All of the materials including videos and sample projects can be downloaded from here .

The source code repository is being hosted on GitHub .

Scope

  • Command Handler
  • Command Dispatcher

Abstract

Command Handler

We can encapsulate our business logic even more by using the ICommand interface which is a common way to start using theCQS (Command & Query separation) pattern in our application.

The interface per se is merely a “marker” and can be defined as follows:

//Marker interface.
public interface ICommand
{
}

Having ICommand in place, we can define as many commands as we want to:

public class CreateUser : ICommand
{
    public string Email { get; set; }
    public string Password { get; set; }
    public string Username { get; set; }    
}

Eventually, we can add define the generic ICommandHandler interface:

public interface ICommandHandler<T> where T : ICommand 
{
    TaskHandleAsync(T command); 
}

And implement the handler for our commands, like this:

public class CreateUserHandler : ICommandHandler<CreateUser>
{
    private readonly IUserService_userService;
    
    public CreateUserHandler(IUserServiceuserService)
    {
        _userService = userService;
    }
 
    public async TaskHandleAsync(CreateUsercommand)
    {
        await _userService.RegisterAsync(command.Email, command.Username, command.Password);
    }
}

Here comes the question – why would you even bother to do that? Usually, the business logic consists more than a single operation to be invoked in order to complete its flow.

Command handlers are a great way to achieve such goal, as we’re able to inject as many services as we need to. Otherwise, we would have to create a separate interfaces dedicated for a single business logic unit, which would do exactly the same (or in the worst case scenario, write such code within our controllers that should be as transparent as possible).

Command Dispatcher

Now, how can we enforce our software to automatically wire up commands to the particular command handlers? And even more importantly, how can we order our controllers, to resolve the proper command handler? At first, let’s define the ICommandDispatcher interface along with its implementation:

public interface ICommandDispatcher
{
    TaskDispatchAsync<T>(T command) where T : ICommand;
}
 
public class CommandDispatcher : ICommandDispatcher
{
    private readonly IComponentContext_context;
 
    public CommandDispatcher(IComponentContextcontext)
    {
        _context = context;
    }
 
    public async TaskDispatchAsync<T>(T command) where T : ICommand
    {
        if(command == null)
        {
            throw new ArgumentNullException(nameof(command),
                $"Command: '{typeof(T).Name}' can not be null.");
        }
        var handler = _context.Resolve<ICommandHandler<T>>();
        await handler.HandleAsync(command);
    }
}

Notice that we’re making use of IComponentContext which is a part of the Autofac Autofac IoC container.

Next step, is to register all of the commands and the appropriate command handlers:

public class CommandModule : Autofac.Module
{
    protected override void Load(ContainerBuilderbuilder)
    {
        var assembly = typeof(CommandModule)
            .GetTypeInfo()
            .Assembly;
 
        builder.RegisterAssemblyTypes(assembly)
                .AsClosedTypesOf(typeof(ICommandHandler<>))
                .InstancePerLifetimeScope();
 
        builder.RegisterType<CommandDispatcher>()
            .As<ICommandDispatcher>()
            .InstancePerLifetimeScope();
    }
}

And finally, we can inject the dispatcher into our controller and redefine our HTTP requets to look as simple as that:

[HttpPost]
public async Task<IActionResult> Post([FromBody]CreateUsercommand)
{
    await CommandDispatcher.DispatchAsync(command);
 
    return Created($"users/{command.Email}", new object());
}

Next

In the next episode, you’ll find out how to configure the application by passing the configuration classes that can be defined and mapped from the appsettings.json .

Moreover, you shall see my efforts in trying to find out why something didn’t work as expected in the first place ;).








New