Question

I am trying to rewrite my app from a service pattern to a command and query pattern (before I move to CQRS). Currently I'm stuck on this blog.

It shows where he moved unit of work commit from the base command into a PostCommitCommandHandlerDecorator, then use Simple Injector to bind them up. The writer also stated that not all commands will require the use of unit of work, which is true in my case because not every command talks to a database but some send emails, etc.

How do I architect my commands and bindings in such a way that only those commands that are required to be wrapped in a unit of work commit will be bound as such by the IoC container?

Was it helpful?

Solution

How do I architect my commands and bindings in such a way that only those commands that are required to be wrapped in a unit of work commit will be bound as such by the IoC container?

First of all, does that really matter that not all handlers use the unit of work? Is it a problem when a unit of work is created, while it isn’t used? Because when there are no performance problems, there’s no need to make your code more complicated.

But let’s assume that it does matter. In that case, the trick is to query the container whether the unit of work is injected somewhere. You can make use of Lazy<T> to get this working. Take a look at the following registration:

Func<IUnitOfWork> uowFactory = 
    () => new MyUnitOfWork(connectionString);

// Register the factory as Lazy<IUnitOfWork>
container.Register<Lazy<IUnitOfWork>>(
    () => new Lazy<IUnitOfWork>(uowFactory), 
    Lifestyle.Scoped);

// Create a registration that redirects to Lazy<IUnitOfWork>
container.Register<IUnitOfWork>(
    () => container.GetInstance<Lazy<IUnitOfWork>>().Value, 
    Lifestyle.Scoped);

For the rest of the article I assume you're building a web application, but the idea will be the same.

With this registration, when the container resolves an object graph with a component that depends on IUnitOfWork, under the covers it will resolve the Lazy<IUnitOfWork> and get its value. We cache the Lazy<IUnitOfWork> per request, so this allows us to have another component that depends on Lazy<IUnitOfWork> and check its IsValueCreated property to see if the IUnitOfWork was injected anywhere.

Now your decorator could look like this:

public class TransactionCommandHandlerDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> decorated;
    private readonly Lazy<IUnitOfWork> lazyUnitOfWork;

    public TransactionCommandHandlerDecorator(
        ICommandHandler<TCommand> decorated,
        Lazy<IUnitOfWork> lazyUnitOfWork)
    {
        this.decorated = decorated;
        this.lazyUnitOfWork = lazyUnitOfWork;
    }

    public void Handle(TCommand command)
    {
        this.decorated.Handle(command);

        if (this.lazyUnitOfWork.IsValueCreated)
        {
            this.lazyUnitOfWork.Value.SubmitChanges();
        }
    }
}

Note however that you still don’t know whether the unit of work is actually used or not, but I think it’s safe to assume that the unit of work will be used when it gets injected. You don’t want to inject an unused dependency.

If that doesn’t cut it, and you want to check whether it is created, you will have to inject a proxy unit of work that allows you to check this. For instance:

public class DelayedUnitOfWorkProxy : IUnitOfWork
{
    private Lazy<IUnitOfWork> uow;

    public DelayedUnitOfWorkProxy(Lazy<IUnitOfWork> uow)
    {
        this.uow = uow;
    }

    void IUnitOfwork.SubmitChanges()
    {
        this.uow.Value.SubmitChanges();
    }

    // TODO: Implement All other IUnitOfWork methods
}

Your configuration will now look like this:

Func<IUnitOfWork> uowFactory = 
    () => new MyUnitOfWork(connectionString);

// Register the factory as Lazy<IUnitOfWork>
container.Register<Lazy<IUnitOfWork>>(
    () => new Lazy<IUnitOfWork>(uowFactory), 
    Lifestyle.Scoped);

// Register the proxy that delays the creation of the UoW
container.Register<IUnitOfWork, DelayedUnitOfWorkProxy>(
    Lifestyle.Scoped);

When a command or any other dependency needs an IUnitOfWork, they will get the DelayedUnitOfWorkProxy, and it is injected with a Lazy<IUnitOfWork>. So after the object graph is created, the unit of work itself will not be created yet. Only when one of the DelayedUnitOfWorkProxy method is called, such instance is created. The decorator will stay the same.

But even this might not be good enough. It is possible that your MVC controller (assuming you are building an ASP.NET MVC application) depends on a query that uses the unit of work, but the command handler does not. In that case you probably still wouldn't want to commit the unit of work, because the command handler (or one of its dependencies) still doesn't use the unit of work.

In that case what you’re actually trying to do is to isolate the execution of command handlers in their own scope. As if they are running in a different App Domain. You want them to be independent of the web request in which they execute.

In that case you need an hybrid lifestyle. With Simple Injector you can leave all your code and configuration in tact, but switch to an hybrid lifestyle like this:

container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
    () => container.GetCurrentLifetimeScope() != null,
    new LifetimeScopeLifestyle(),
    new WebRequestLifestyle());

Func<IUnitOfWork> uowFactory = 
    () => new MyUnitOfWork(connectionString);

// Register the factory as Lazy<IUnitOfWork>
container.Register<Lazy<IUnitOfWork>>(
    () => new Lazy<IUnitOfWork>(uowFactory), 
    Lifestyle.Scoped);

// Register a proxy that depends on Lazy<IUnitOfWork>    
container.Register<IUnitOfWork, DelayedUnitOfWorkProxy>(
    Lifestyle.Scoped);

An hybrid lifestyle is a composite of two (or more) lifestyles and it contains a predicate delegate that the container will call to check which lifestyle should be applied.

With just this configuration nothing will happen, because the LifetimeScopeLifestyle requires you to explicitly start and stop a new scope. Without a scope the container.GetCurrentLifetimeScope() method will always return null, which means that the hybrid lifestyle will always pick the WebRequestLifestyle.

What you need is to start a new lifetime scope just before you resolve a new command handler. As always, this can be done by defining a decorator:

private sealed class LifetimeScopeCommandHandlerDecorator<T>
    : ICommandHandler<T>
{
    private readonly Container container;
    private readonly Func<ICommandHandler<T>> decorateeFactory;

    public LifetimeScopeCommandHandlerDecorator(Container container,
        Func<ICommandHandler<T>> decorateeFactory)
    {
        this.decorateeFactory = decorateeFactory;
        this.container = container;
    }

    public void Handle(T command)
    {
        using (this.container.BeginLifetimeScope())
        {
            var decoratee = this.decorateeFactory.Invoke();
            decoratee.Handle(command);
        }
    }
}

You should register this decorator as last decorator (outer most decorator). Instead of depending on an ICommandHandler<T> this decorator depends on an Func<ICommandHandler<T>>. This makes sure that the decorated command handler will only get resolved when the Func<T> delegate is invoked. This postpones the creation and and allows the creation of a lifetime scope first.

Since this decorator depends on two singletons (both the container and the Func<T> are singletons), the decorator itself can also be registered as singleton. This is what your configuration might look like:

// Batch register all command handlers
container.Register(
    typeof(ICommandHandler<>), 
    typeof(ICommandHandler<>).Assembly);

// Register one or more decorators
container.RegisterDecorator(
    typeof(ICommandHandler<>), 
    typeof(TransactionCommandHandlerDecorator<>));

// The the lifetime scope decorator last (as singleton).
container.RegisterDecorator(
    typeof(ICommandHandler<>), 
    typeof(LifetimeScopeCommandHandlerDecorator<>),
    Lifestyle.Singleton);

This will effectively isolate the unit of work used by commands from any unit of work that is created outside the context of a command handler within the rest of the request.

OTHER TIPS

There is a simple way to achieve what you are asking. There are overloaded versions of the RegisterDecorator extension method that accept a Predicate which, in combination with a marker interface, can be used to selectively apply a decorator.

Here's an example in code:

public interface ICommandHandler<T> where T : class { }
public interface IDontUseUnitOfWork { }

public class MyCommand { }

public class MyCommandHandler : 
    ICommandHandler<MyCommand>, IDontUseUnitOfWork { }

public sealed class UnitOfWorkCommandDecorator<T> :
    ICommandHandler<T> where T : class
{
    public UnitOfWorkCommandDecorator(ICommandHandler<T> decorated) { }
}

And the registration to apply the UnitOfWorkCommandDecorator to command handlers except those that are tagged with the IDontUseUnitOfWork interface:

container.RegisterDecorator(
    typeof(ICommandHandler<>), 
    typeof(UnitOfWorkCommandDecorator<>),
    x => !typeof(IDontUseUnitOfWork).IsAssignableFrom(x.ImplementationType));

This predicate feature is very useful and well worth getting to grips with.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top