In my post on how to simplify code by using composition instead of an AOP-framework I showed a way of substituting attribute based programming with a more composable paradigm. The result of that transformation will be my starting point for today’s post. For reference, I’m including that code here again:
public class TaskCommandHandlers : ICommandHandler<CreateTask>,
ICommandHandler<MarkTaskDone>
{
ITaskRepository _repo;
INotificationService _notificationService
public TaskService(ITaskRepository taskRepository, INotificationService notificationService)
{
_repo = taskRepository;
_notificationService = notificationService;
}
public void Handle(CreateTask command)
{
repo.Insert(new Task(command.Name));
}
public void Handle(MarkTaskDone command)
{
var task = _repo.Get(command.TaskId);
task.Status = TaskStatus.Done;
task.ModifiedBy = command.UserName;
_repo.Update(task);
_notificationService.NotifyUser(command.UserName);
}
}
What we did was combining the different parameters so that we have a common interface. This allows us to compose our code in different ways using the decorator pattern. This has certain advantages as discussed in the post, but there are still a few things that I don’t like about this code:
- There’s a lot of code that doesn’t really add value. In fact only 8 lines (the method bodies) out of a total of 25 are relevant. On top of that we have an interface (ICommandHandler).
- The dependencies are scoped incorrectly. They are not really dependencies for the entire class but localized to the separate methods. (Although the repo is used in both methods, in any instance of this class, conceptually it belongs to each of the methods separately.)
- A class has state and behavior, but this class does not really have any state apart from the dependencies, which are wrongly scoped.
To solve this, we could pass the dependencies into the methods instead of in the constructor:
public class TaskCommandHandlers : ICommandHandler<CreateTask>,
ICommandHandler<MarkTaskDone>
{
public void Handle(CreateTask command, ITaskRepository repo)
{
repo.Insert(new Task(command.Name));
}
public void Handle(MarkTaskDone command,
ITaskRepository repo,
INotificationService notificationService)
{
var task = repo.Get(command.TaskId);
task.Status = TaskStatus.Done;
task.ModifiedBy = command.UserName;
repo.Update(task);
notificationService.NotifyUser(command.UserName);
}
}
This already looks a bit better, but there’s a problem: now we don’t have a common interface anymore. To solve this, we could apply the same technique as we did in getting to the common interface ie: combining the parameters into a new type. That wouldn’t be a good idea though. Instead, let’s first move away from the class-behavior and declare these code block as static Action‘s:
public class TaskCommandHandlers
{
public static readonly Action<CreateTask, ITaskRepository> CreateNewTask = (command, repo) =>
repo.Insert(new Task(command.Name));
public static readonly Action<MarkTaskDone, ITaskRepository, INotificationService> MarkTaskAsDone = (command, repo, notificationService) =>
{
var task = repo.Get(command.TaskId);
task.Status = TaskStatus.Done;
task.ModifiedBy = command.UserName;
repo.Update(task);
notificationService.NotifyUser(command.UserName);
};
}
In this code:
- There’s no constructor
- There are no interfaces
- Dependencies are correctly scoped
- We’ve reduced the ratio of important lines/overhead to 8/14 instead of 8/25.
There’s still the issue of a non-conforming interface though. At some point we do need to call these methods and we’d like to pass in just the command and have the other dependencies resolved automatically. Our client needs either an Action
Partial application explained
Before I show how to do this, I want to give a short explanation of what partial application is. Partial application is a concept that stems from Functional Programming (FP), but since C# has some elements of FP, we can use it here as well.
partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity (source: wikipedia)
Here we can see a sample of partial application in action:
Func<int, int, int> sum = (a, b) => a + b;
Func<int, int> add10To = a => sum(a, 10);
sum(5, 10);
add10To(5);
In the above example you can see how we create a Func (sum) which accepts two ints and returns an int. On the second line, we create a Func called add10To, which accepts a single int and returns an int. Inside that Func, we call the original function, with the single parameter and the value 10. What we have done is fixed one of the arguments of the original function to a fixed value. This is exactly what we need to solve our problem above.
Partial application as a DI mechanism
Knowing what partial application is, we can now create an Action
var repository = new TaskRepository();
var notificationService = new NotificationService();
Action<CreateTask> create = command =>
TaskCommandHandlers.CreateNewTask(command, repository);
Action<MarkTaskDone markDone = command =>
TaskCommandHandlers.MarkTaskAsDone(command, repository, notificationService);
Partial application in the composition root
To be able to resolve these actions we need to declare them in our composition root. Let’s look at how we would do that in an ASP.NET web API project. Because we don’t want to inject multiple Action
public class TaskController : ApiController
{
[HttpPost]
public void CreateTask(CreateTask command) =>
Commands.Dispatch(command);
[HttpPost]
public void MarkTaskAsDone(MarkTaskDone command) =>
Commands.Dispatch(command);
}
The Commands-class is a static class with public static methods (see below). The TaskController is in fact just a regular controller with an empty default constructor. We won’t ever need to inject anything in here, because the only thing a controller does is declare endpoints and from these endpoints we dispatch commands. For query operations, we can follow the same pattern as with the commands, but I’ve omitted that part for the sake of brevity.
Note about testing: Some will argue that you can’t substitute the dispatcher in unit tests. Personally, I wouldn’t test the controller. All you would be testing is whether it dispatches the command that you pass in, which is not a very valuable test.
The dispatcher needs to be able to register handlers and dispatch commands to the correct handlers:
public class Commands
{
static readonly Dictionary<Type, Action<ICommand>> handlers =
new Dictionary<Type, Action<ICommand>>();
public static void Register<T>(Action<T> handler) where T : ICommand =>
handlers.Add(typeof(T), x => handler((T) x));
public static void Dispatch(ICommand command) =>
handlers[command.GetType()](command);
}
In the register-method we save all handlers in a dictionary, with the key based on their type. When we’re dispatching a command, we look it up in the dictionary and call the action. Our composition root can then be as follows:
public class CompositionRoot
{
public static void Bootstrap()
{
// Create the services we need
// use lazy here, because it’s expensive to construct (suggestion by FizixMan on Reddit)
var repository = new Lazy<TaskRepository>(new TaskRepository());
var notificationService = new NotificationService();
// Use partial application to fix the extra parameters the handlers need
// and create and register an Action<CreateTask> and an Action<MarkTaskDone>
Commands.Register<CreateTask>(createTask =>
TaskCommandHandlers.CreateNewTask(createTask, repository.Value);
Commands.Register<MarkTaskDone>(markAsDone =>
TaskCommandHandlers.MarkTaskAsDone(markAsDone, repository.Value, notificationService));
}
}
In the composition root we create and register the handlers we’re going to need. This is where we close the extra parameters that the handlers need and turn them into plain Action
Managing lifetime with Partial Application
A common treat of most containers is the ability to manage the lifecycle of a dependency. With partial application, this is built-in and it allows you to create custom lifecycles as well. There’s no need to learn special syntax, it’s just regular C#. To explain lifetime management, I’m going to use a slightly different graph:
Handler - CreateTask - Repository - NotificationService - Repository - SomeService - Repository
In the following examples I will focus on the lifetime management of the repository.
Singleton
For a singleton we need to instantiate the repository inside the Bootstrap method, but outside of the actual handlers, so it will only get instantiated once (when the method is called, on start up). Here the repository is created only once and is then reused every time we invoke the action.
public static void BootsTrap()
{
var repository = new TaskRepository();
var notificationService = new NotificationService(repository);
var someService = new someService(repository);
Commands.Register<CreateTask>(createTask =>
TaskCommandHandlers.CreateNewTask(createTask,
repository,
notificationService,
someService);
}
Transient
Here every time the action is invoked, all services are instantiated.
public static void BootsTrap()
{
dispatcher.Register<CreateTask>(createTask =>
TaskCommandHandlers.CreateNewTask(createTask,
new TaskRepository(),
new NotificationService(
new TaskRepository()
),
new SomeService(
new TaskRepository()
);
}
Per request
Notice the subtle difference with the singleton: the services are created inside the Action
public static void BootsTrap()
{
Commands.Register<CreateTask>(createTask =>
{
var repository = new TaskRepository();
var notificationService = new NotificationService(repository);
var someService = new SomeService(repository);
TaskCommandHandlers.CreateNewTask(createTask,
repository,
notificationService,
someService);
};
}
Custom lifetime
Since we’re using pure C#, we can mix and match any instantiation policy we want. In the following (contrived) example:
- notificationService and someService have a per request lifetime.
- notificationService and someService share the same singleton instance of the repository.
- The handler gets a new repository every time (transient).
public static void BootsTrap()
{
var repository = new TaskRepository();
Commands.Register<CreateTask>(createTask =>
{
var notificationService = new NotificationService(repository);
var someService = new SomeService(repository);
TaskCommandHandlers.CreateNewTask(createTask,
new TaskRepository(),
notificationService,
someService);
};
}
Composition
In my post simplify code by using composition I showed how to move from attribute based programming to a more flexible composition based programming. This composability is not lost when we use partial application instead of constructor injection. To add logging to the CreateTask handler, we create a new handler:
class LoggingHandlers
{
public static Action<ICommand, Action<ICommand>> Log = (command, next) =>
{
Log(command); // do custom logging here
next(command);
}
}
Now we use partial application again to plug this in from within the composition root:
Commands.Register<CreateTask>(createTask =>
LoggingHandlers.Log(createTask, createTask =>
TaskCommandHandlers.CreateNewTask(createTask, repository));
Conclusion
Partial application is a very flexible and powerful pattern. When applied to DI, it focuses the attention on code that matters, correctly scopes dependencies and removes the cruft that constructor injection sometimes brings with it. It allows the same usage patterns of a DI-container with regards to lifetime management and it does not inhibit composability.
Update after comments on Reddit by FizixMan:
- The static Actions on the handler should be readonly, you don’t want other code to overwrite those
- In case construction of a dependency is costly, you can consider using a Lazy
to speed up application start up.