Kenneth Truyers

Using partial application for dependency injection

Introduction

Kenneth Truyers

Kenneth Truyers


best practices patterns simplicity

Using partial application for dependency injection

Posted by Kenneth Truyers on .
Featured

best practices patterns simplicity

Using partial application for dependency injection

Posted by Kenneth Truyers on .

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 or an Action, but what we have is an Action<CreateTask, ITaskRepository> and an Action<MarkTaskDone, ITaskRepository, INotificationService>. For this we are going to use partial application.

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 as follows:

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‘s in our controllers, we will be creating a dispatcher with static methods. A controller will look like this:

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’s. We only need to call the Bootstrap method once when the application starts. This frees us from having to deal with Web API-specific code and this composition root is in fact portable to any other type of project.

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 instead of in the method itself. So, for every time we call the Action, we’ll create a new the repository, but that instance will be shared by all services. (NOTE: Technically this is not per request, if not per graph, but since we will model our controller to send a single command per request, in practice it will be the same. You could create a pure per request lifetime by using the HttpContext.Current.Items bag, but I’ll leave that as an exercise 🙂 )

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.
Kenneth Truyers

Kenneth Truyers

View Comments...