Task Pattern and Dependency Injection

Ayende has written several articles about the Command/Task pattern that he uses to organize his code and allow limited background processing in his blogging platform, RacoonBlog.

I've found his suggestions and the command/task pattern to be quite valuable in keeping my code well organized, but I don't like his testing method which involves base classes, manual property injection, and alternate execution delegates. I wanted an approach that easily allowed me to use dependency injection to increase flexibility and test-ability with a mocking framework.

A very simplified version of Ayende's task structure is outlined below. The SendThanksEmail clearly depends on an EmailGateway property that Ayende's BackgroundTask provides.

public class SendThanksEmail : BackgroundTask
{
    private readonly string to;

    public SendThanksEmail(string to)
    {
        this.to = to;
    }

    public void Execute()
    {
        var mailMessage = this.BuildMailMessage();

        // How do we inject EmailGateway?
        this.EmailGateway.Send(mailMessage);
    }
}

public abstract class BackgroundTask
{   
    // Set by task executor or instantiated in the constructor
    public IEmailGateway EmailGateway { get; set; }

    public abstract void Execute();
}

This task would be instantiated and used in a controller as follows:

public ActionResult MyAction(ViewModel viewModel)
{
    var sendThanksEmail = new SendThanksEmail(viewModel.To);
    this.BackgroundTaskExecutor.ExecuteLater(sendThanksEmail);
    return this.RedirectToAction("Thanks");
}

The call to BackgroundTaskExecutor.ExecuteLater queues the task to be executed at a later time, which is inconsequential to this discussion.

Given the above scenario, how can we inject an IEmailGateway into the task? The two traditional methods of injection, constructor and property injection, are both awkward to use here. Constructor injection is awkward because requiring the SendThanksEmail constructor to accept an IEmailGateway means that an IEmailGateway must be available to the controller that instantiates the task. But by requiring the controller have access to the IEmailGateway, we're losing the greatest benefits of using the tasks, separation of concerns and encapsulation.

The second traditional option is to use property injection and expose a public IEmailGateway property on SendThanksEmail. In this scenario, the BackgroundTaskExecutor would be responsible for injecting the property dependencies before calling Execute(). This is an improvement because the controller isn't responsible for dependencies it doesn't directly use, but property injection makes for awkward and unclear APIs.

A solution that is testable, with a clean API, is method parameter injection.

Here are the interfaces I'll use:

public interface IBackgroundTask
{
}

public interface IBackgroundTaskExecutor
{
    void ExecuteLater(IBackgroundTask backgroundTask);
    void ExecuteTasks();
}

public interface IEmailGateway
{
    void SendEmail(MailMessage mailMessage);
}

You've probably noticed that IBackgroundTask doesn't doesn't define an Execute method. This is because the Execute method's signature will be different for every task and is where we will inject the task's dependencies. In this case we'll rely on the convention of the method being called Execute.

Here's the new testable SendThanksEmail task:

public class SendThanksEmail : IBackgroundTask
{
    private readonly string to;

    public SendThanksEmail(string to)
    {
        this.to = to;
    }

    public void Execute(IEmailGateway emailGateway)
    {
        var mailMessage = this.BuildMailMessage();
        emailGateway.Send(mailMessage);
    }
}

The core of the solution is the UnityBackgroundTaskExecutor. I'm using Unity as my container, but this functionality is not specific to Unity.

public class UnityBackgroundTaskExecutor : IBackgroundTaskExecutor
{
    private readonly IUnityContainer container;
    private readonly List<IBackgroundTask> backgroundTasks;

    public UnityBackgroundTaskExecutor(IUnityContainer container)
    {
        this.container = container;
        this.backgroundTasks = new List<IBackgroundTask>();
    }

    public void ExecuteLater(IBackgroundTask backgroundTask)
    {
        this.backgroundTasks.Add(backgroundTask)
    }

    public void ExecuteTasks()
    {
        foreach (var backgroundTask in backgroundTasks)
        {
            // Use Reflection to get the Execute method and its parameters
            var executeMethodInfo = backgroundTask.GetType().GetMethod("Execute");
            var parameterInfos = executeMethodInfo.GetParameters();

            // Resolve the parameters from the IoC container and invoke the Execute method
            var parameters = parameterInfos.Select(parameterInfo => this.container.Resolve(parameterInfo.ParameterType)).ToArray();
            executeMethodInfo.Invoke(backgroundTask, parameters);
        }
    }
}

For each task, the UnityBackgroundTaskExecutor inspects the Execute method for its parameters, resolves them from the container, and then invokes the task's Execute method.

A small amount of reflection and a simple naming convention allow us to create tasks that can be easily tested with a mocking library.