Query Objects with a Mediator

Mediator

In my previous blog Query Objects instead of Repositories, I demonstrated creating query objects and handlers to encapsulate and execute query logic instead of polluting a repository with both read and write methods.  Since we have moved away from repositories and are now using query objects, we will introduce the Mediator pattern. It will allows have a common interface that can be injected into our controller or various parts of our application. The mediator will delegate our query objects to the appropriate handler that will perform the query and return the results.

First we will create an interface that will be used on all of our query objects.

public interface IQuery<out TResponse> { }

Now we need to create an interface that all of our query handlers will implement.

public interface IHandleQueries<in TQuery, out TResponse>
	where TQuery : IQuery<TResponse>
{
	TResponse Handle(TQuery query);
}

Next we will create our Mediator interface. Most examples you will see that are implementing command handlers generally are showing an IFakeBus or something similar. The difference being that generally in the Bus implementation there is no return type. On the query side, our intent is to return data.

public interface IMediate
{
	TResponse Request<TResponse>(IQuery<TResponse> query);
}

There are many ways you can implement your mediator. As an example:

public class Mediator : IMediate
{
	public delegate object Creator(Mediator container);

	private readonly Dictionary<Type, Creator> _typeToCreator = new Dictionary<Type, Creator>();

	public void Register<T>(Creator creator)
	{
		_typeToCreator.Add(typeof(T), creator);
	}

	private T Create<T>()
	{
		return (T)_typeToCreator[typeof(T)](this);
	}

	public TResponse Request<TResponse>(IQuery<TResponse> query)
	{
		var handler = Create<IHandleQueries<IQuery<TResponse>, TResponse>>();
		return handler.Handle(query);
	}
 }

Now that we have our interfaces and mediator implementation, we need to modify our existing queries and handlers.

public class ProductDetailsQuery : IQuery<ProductDetailModel>
{
	public Guid ProductId { get; private set; }

	public ProductDetailsQuery(Guid productId)
	{
		ProductId = productId;
	}
}

public class ProductDetailQueryHandler : IHandleQueries<ProductDetailsQuery, ProductDetailModel>
{
	private DbContext _db;
 
	public ProductDetailQueryHandler(DbContext db)
	{
		_db = db;
	}
 
	public ProductDetailModel Handle(ProductDetailsQuery query)
	{
		var product = (from p in _db.Products where p.ProductId == query.ProductId).SingleOrDefault();
		if (product == null) {
			throw new InvalidOperationException("Product does not exist.");
		}
 
 		var relatedProducts = (from p in _db.RecommendedProducts where p.PrimaryProductId == query.ProductId);
 
 		return new ProductDetailsModel
		{
			Id = product.Id,
			Name = product.Name,
			Price = product.Price,
			PriceFormatted = product.Price.ToString("C"),
			RecommendedProducts = (from x in relatedProducts select new ProductDetailModel.RecommendedProducts {
				ProductId = x.RecommendedProductId,
				Name = x.Name,
				Price = x.Price,
				PriceFormatted = x.Price.ToString("C")
			})
		};
	}
 }

Now in our controller, instead of either creating a new instance of the query handler in our controllers or having all them injected into the constructor, we now simply inject the mediator.

public class ProductController : Controller
{
	private IMediate _mediator;
	
	public ProductController(IMediate mediator)
	{
		_mediator = mediator;
	}
	
	public ViewResult ProductDetails(ProductDetailQuery query)
	{
		var model = _mediator.Request(query);
		return View(model);
	}
}

As before, we have encapsulated the generation of our view model into its own object but now a common interface in a mediator to handle the incoming query object requests.

Query Objects instead of Repositories

QueryThe repository pattern is often used to encapsulate simple and sometimes rather complex query logic.   However, it has also been morphed into handling persistence and is often used as another layer of abstraction from your data mapping layer.   This blog post show you how to slim down and simplify your repositories or possibly eliminate them all together by using query objects.

A typical repository will look something like this:

public interface IProductRepository
{
	void Insert(Product product);
	void Delete(Product product);
	IEnumerable<Product> GetById(Guid id);
	IEnumerable<Product> GetAllActive();
	IEnumerable<Product> FindByName(string name);
	IEnumerable<Product> FindBySku(string name);
	IEnumerable<Product> Find(string keyword, int limit, int page);
	IEnumerable<Product> GetRelated(Guid id);
}

Each of the Get/Find methods implemented above would encapsulate a specific a query.  This type of repository would most likely be used to then transform the data returned from a set of methods into a View Model which would then be passed to our view or serialized and sent back to the caller (browser).  As an example of passing the model to a view in ASP.NET MVC, it would look something like this:

public ViewResult ProductDetails(Guid productId)
{
	var product = _productRepository.GetById(productId);
	var relatedProducts = _productRepository.GetRelated(productId);
	
	var model = new ProductDetailsModel
	{
		Id = product.Id,
		Name = product.Name,
		Price = product.Price,
		PriceFormatted = product.Price.ToString("C"),
		RecommendedProducts = (from x in relatedProducts select new ProductDetailModel.RecommendedProducts {
				ProductId = x.RecommendedProductId,
				Name = x.Name,
				Price = x.Price,
				PriceFormatted = x.Price.ToString("C")
			})
	};

	return View(model);
}

As I’ve mentioned before, I believe you should think of your MVC framework as an HTTP interface to your application.  Regardless if you are returning HTML or JSON, the generation of your View Model should not be coupled to your MVC framework.

Query Objects

In the example above, I want to extract the generation of my view model info a query object.  A query object is similar to a command object for processing behavior in our domain.  Our query object will now look like this:

public class ProductDetailsQuery
{
	public Guid ProductID { get; private set; }
	
	public ProductDetailQuery(Guid productId)
	{
		ProductId = productId
	}
}

In order to execute our query, we will implement in a query handler.

public class ProductDetailQueryHandler
{
	private DbContext _db;
	
	public ProductDetailQueryHandler(DbContext db)
	{
		_db = db;
	}
	
	public ProductDetailModel Handle(ProductDetailQuery query)
	{
		var product = (from p in _db.Products where p.ProductId == query.ProductId).SingleOrDefault();
		if (product == null) {
			throw new InvalidOperationException("Product does not exist.");
		}
		
		var relatedProducts = (from p in _db.RecommendedProducts where p.PrimaryProductId == query.ProductId);
		
		return new ProductDetailsModel
		{
			Id = product.Id,
			Name = product.Name,
			Price = product.Price,
			PriceFormatted = product.Price.ToString("C"),
			RecommendedProducts = (from x in relatedProducts select new ProductDetailModel.RecommendedProducts {
				ProductId = x.RecommendedProductId,
				Name = x.Name,
				Price = x.Price,
				PriceFormatted = x.Price.ToString("C")
			})
		};
	}
}

Now we have encapsulated the generation of our view model which can be used in our controller.

public ViewResult ProductDetails(ProductDetailQuery query)
{
	var model = _queryHandler(query);
	return View(model);
}

Now our controller is responsible for delegating the call to generate the model and action result or serialization.  In my next post I will take this a step further by introducing a common interface for our query handler in order to accept multiple query objects and  return types.

Throw Out Your Dependency Injection Container

Dependency Injection

Dependency injection containers (aka inversion of control containers) seem to be common in most modern applications.  There is no argument against the value dependency injection, but I do have a couple arguments against using a dependency injection container.  Like many other design patterns and practices, over time the development community seems to forget the original problem the pattern or practice was solving.

Constructor & Setter Injection

Passing your dependencies via the constructor is generally a better way of injecting dependencies instead of  setters. Constructor injection gives you a much clearer definition of what dependencies are needed in order to construct the object into a valid state.  My dependencies fields are usually readonly, to prevent them from being externally set after object creation.

Regardless if you use constructor or setter injection with your container of choice, there is often one injection method that is seemingly rarely used or mentioned.  Pass your dependency to the method that requires it.

How often have you seen a constructor take a pile of dependencies via it’s constructor, to which those dependencies were used in a limited amount of methods.  I often see this when looking at CQRS Command Handlers.

class InventoryHandler
{
	private readonly IRepository _repository;
	private readonly IBus _bus;
	private readonly IValidateInventory _validation;
	
	public InventoryHandler(IRepository repository, IBus bus, IValidateInventory validation)
	{
		_repository = repository;
		_bus = bus
		_validation = validation;
	}

	public void Handle(ReceiveInventory cmd)
	{
		if (!_validation.IsAvailable(cmd.ProductId)) {
			throw new InvalidOperationException("Cannot receive inventory");
		}

		// Receive Product into Inventory
		var inventory = _repository.GetById(cmd.ProductId);
		inventory.Receive(cmd.Quantity, cmd.UnitCost);
	}

	public Handle(RemoveInventory cmd)
	{
		// Remove product from inventory
		var inventory = _repository.GetById(cmd.ProductId);
		inventory.RemoveInventory(cmd.Quantity);

		// Pub/Sub to notify other bounded context of inventory removal
		_bus.Send(new InventoryRemovedMessage(cmd.InventoryId));
	}
}

In this simplified example, IRepository is used in both Handle() methods. However, IBus & IValidateInventory are both only used in one method each.

Instead of passing the dependencies via constructor, pass the required dependencies to the method that requires it.

class InventoryHandler
{
	private readonly IRepository _repository;
	
	public InventoryHandler(IRepository repository)
	{
		_repository = repository;
	}

	public void Handle(IValidateInventory validation, ReceiveInventory cmd)
	{
		if (!validation.IsAvailable(cmd.ProductId)) {
			throw new InvalidOperationException("Cannot receive inventory");
		}

		// Receive Product into Inventory
		var inventory = _repository.GetById(cmd.ProductId);
		inventory.Receive(cmd.Quantity, cmd.UnitCost);
	}

	public Handle(IBus bus, RemoveInventory cmd)
	{
		// Remove product from inventory
		var inventory = _repository.GetById(cmd.ProductId);
		inventory.RemoveInventory(cmd.Quantity);

		// Pub/Sub to notify other bounded context of inventory removal
		bus.Send(new InventoryRemovedMessage(cmd.InventoryId));
	}
}

 

Nested Dependencies

The primary reason why I prefer not to use a dependency injection container is because it potentially masks a code smell.  Nested dependencies or over abstraction can add complexity by adding unnecessary layers.

Have you seen something similar to this before?

public class MyService(IRepository repostiory) { ... }
public class Repository(IUnitOfWork unitOfWork) { ... }
public class UnitOfWork(IDbContext dbContext) { ... }
public class DbContext(IDbConnection dbConnection) { ... }
public class DbConnection(string connectionString) { ... }

Code SmellIf you are using a dependency injection container, you may not have noticed the excessive and unneeded abstraction layers in parts of you application.  If you had to manually wire up up these nested dependencies through all the layers, it would be really painful.

Masking the pain by using a dependency injection container is making your application more complex.

Take a look at your application and see if you can remove your dependency injection container.   If you can, then what benefits did it provide?  If you can’t, ask yourself if you really need all those layers.