Externalising dependencies with Dependency Injection in .NET part 4: logging part 1

Introduction

In this post of this series we looked at ways to remove caching logic from our ProductService class. In the previous post we saw how to hide reading from a configuration file. We’ll follow in a similar fashion in this post which takes up logging. A lot of the techniques and motivations will be re-used and not explained again.

We’ll build upon the demo app we started on so have it ready in Visual Studio.

Logging

Logging is a wide area with several questions you need to consider. What needs to be logged? Where should we save the logs? How can the log messages be correlated? We’ll definitely not answer those questions here. Instead, we’ll look at techniques to call the logging implementation.

I’d like to go through 3 different ways to put logging into your application. For the demo we’ll first send the log messages to the Console window for an easy start. After that, we’ll propose a way of implementing logging with log4net. The material is too much for a single post so I’ve decided to divide this topic into 2 posts.

Starting point

If you ever had to log something in a professional .NET project then chances are that you used Log4Net. It’s a mature and widely used logging framework. However, it’s by far not the only choice. There’s e.g. NLog and probably many more.

If you recall the first solution for the caching problem we put the caching logic directly inside ProductService.GetProduct:

public GetProductResponse GetProduct(GetProductRequest getProductRequest)
{
	GetProductResponse response = new GetProductResponse();
	try
	{
		string storageKey = "GetProductById";
		ObjectCache cache = MemoryCache.Default;
		Product p = cache.Contains(storageKey) ? (Product)cache[storageKey] : null;
		if (p == null)
		{
			p = _productRepository.FindBy(getProductRequest.Id);
			CacheItemPolicy policy = new CacheItemPolicy() { AbsoluteExpiration = DateTime.Now.AddMinutes(5) };
			cache.Add(storageKey, p, policy);
		}
		response.Product = p;
		if (p != null)
		{
			response.Success = true;
		}
		else
		{
			response.Exception = "No such product.";
		}
	}
	catch (Exception ex)
	{
		response.Exception = ex.Message;
	}
	return response;
}

We then also discussed the disadvantages of such a solution, like diminished testability and flexibility. We could follow a similar solution for the logging with log4net with direct calls from ProductService like this:

var logger = logSource.GetLogger();
var loggingEvent = new LoggingEvent(logSource.GetType(), logger.Logger.Repository, logger.Logger.Name, Level.Info, "Code starting", null);
logger.Logger.Log(loggingEvent);

…which would probably be factored out to a different method but the strong dependency on and tight coupling to log4net won’t go away. We could have similar code for NLog and other logging technologies out there. Then some day the project leader says that the selected technology must change because the one they used on a different project is much more powerful. Then the developer tasked with changing the implementation at every possible place in the code won’t have a good day out.

The logging interface

As we saw in the previous post the key step towards an OOP solution is an abstraction which hides the concrete implementation. This is not always a straightforward step. In textbooks it always looks easy to create these interfaces because they always give you a variety of concrete implementations beforehand. Then you’ll know what’s common to them and you can put those common methods in an interface. In reality, however, you’ll always need to think carefully about the features that can be common across a variety of platforms: what should every decent logging framework be able to do at a minimum? What should a caching technology be able to do? Etc., you can ask similar questions about every dependency in your code that you’re trying to factor out. The interface should find the common features and not lean towards one specific implementation so that it becomes as future-proof as possible.

Normally any logging framework should be able to log messages, message levels – e.g. information or fatal – and possibly exceptions. Insert a new folder called Logging to the Infrastructure layer and add the following interface into it:

public interface ILoggingService
{
	void LogInfo(object logSource, string message, Exception exception = null);
	void LogWarning(object logSource, string message, Exception exception = null);
	void LogError(object logSource, string message, Exception exception = null);
	void LogFatal(object logSource, string message, Exception exception = null);
}

This should be enough for starters: the source where the logging happens, the message and an exception. The level is represented by the method names.

Logging to the console

As promised above, we’ll take it easy first and send the log messages directly to the console. So add the following implementation to the Logging folder:

public class ConsoleLoggingService : ILoggingService
{
	private ConsoleColor _defaultColor = ConsoleColor.Gray;

	public void LogInfo(object logSource, string message, Exception exception = null)
	{
		Console.ForegroundColor = ConsoleColor.Green;
		Console.WriteLine(string.Concat("Info from ", logSource.ToString(), ": ", message));
		PrintException(exception);
		ResetConsoleColor();
	}

	public void LogWarning(object logSource, string message, Exception exception = null)
	{
		Console.ForegroundColor = ConsoleColor.Yellow;
		Console.WriteLine(string.Concat("Warning from ", logSource.ToString(), ": ", message));
		PrintException(exception);
		ResetConsoleColor();
	}

	public void LogError(object logSource, string message, Exception exception = null)
	{
		Console.ForegroundColor = ConsoleColor.DarkMagenta;
		Console.WriteLine(string.Concat("Error from ", logSource.ToString(), ": ", message));
		PrintException(exception);
		ResetConsoleColor();
	}

	public void LogFatal(object logSource, string message, Exception exception = null)
	{
		Console.ForegroundColor = ConsoleColor.Red;
		Console.WriteLine(string.Concat("Fatal from ", logSource.ToString(), ": ", message));
		PrintException(exception);
		ResetConsoleColor();
	}

	private void ResetConsoleColor()
	{
		Console.ForegroundColor = _defaultColor;
	}

	private void PrintException(Exception exception)
	{
		if (exception != null)
		{
			Console.WriteLine(string.Concat("Exception logged: ", exception.Message));
		}
	}
}

That should be quite straightforward I believe.

Solution 1: decorator

We saw an example of the Decorator pattern in the post on caching referred to in the intro and we’ll build on that. We’ll extend the original ProductService implementation to include both caching and logging. Add the following decorator to the Services folder of the Console app layer:

public class LoggedProductService : IProductService
{
	private readonly IProductService _productService;
	private readonly ILoggingService _loggingService;

	public LoggedProductService(IProductService productService, ILoggingService loggingService)
	{
		if (productService == null) throw new ArgumentNullException("ProductService");
		if (loggingService == null) throw new ArgumentNullException("LoggingService");
		_productService = productService;
		_loggingService = loggingService;
	}

	public GetProductResponse GetProduct(GetProductRequest getProductRequest)
	{
		GetProductResponse response = new GetProductResponse();
		_loggingService.LogInfo(this, "Starting GetProduct method");
		try
		{
			response = _productService.GetProduct(getProductRequest);
			if (response.Success)
			{
				_loggingService.LogInfo(this, "GetProduct success!!!");
			}
			else
			{
				_loggingService.LogError(this, "GetProduct failure...", new Exception(response.Exception));
			}
		}
		catch (Exception ex)
		{
			response.Exception = ex.Message;
			_loggingService.LogError(this, "Exception in GetProduct!!!", ex);
		}
		return response;
	}
}

You’ll recall the structure from the Caching decorator. We hide both the product and logging service behind interfaces. We delegate the product retrieval to the product service and logging to the logging service. So if you’d like to add logging to the original ProductService class then you can have the following code in Main:

IProductService productService = new ProductService(new ProductRepository());
IProductService loggedProductService = new LoggedProductService(productService, new ConsoleLoggingService());
GetProductResponse getProductResponse = loggedProductService.GetProduct(new GetProductRequest() { Id = 2 });
if (getProductResponse.Success)
{
	Console.WriteLine(string.Concat("Product name: ", getProductResponse.Product.Name));
}
else
{
	Console.WriteLine(getProductResponse.Exception);
}

If you run this code then you’ll see an output similar to this:

Info messages from logging service

If you run the code with a non-existent product ID then you’ll see an exception as well:

Exception from logging service

If you’d then like to add both caching and logging to the plain ProductService class then you can have the following test code:

IProductService productService = new ProductService(new ProductRepository());
IProductService cachedProductService = new CachedProductService(productService, new SystemRuntimeCacheStorage());
IProductService loggedCachedProductService = new LoggedProductService(cachedProductService, new ConsoleLoggingService());
GetProductResponse getProductResponse = loggedCachedProductService.GetProduct(new GetProductRequest() { Id = 2 });
if (getProductResponse.Success)
{
	Console.WriteLine(string.Concat("Product name: ", getProductResponse.Product.Name));
}
else
{
	Console.WriteLine(getProductResponse.Exception);
}

getProductResponse = loggedCachedProductService.GetProduct(new GetProductRequest() { Id = 2 });
			
Console.ReadKey();

Notice how we build up the compound decorator loggedCachedProductService from productService and cachedProductService in the beginning of the code. You can step through the code and you’ll see how we print the log messages, check the cache and retrieve the product from ProductService if necessary.

Solution 2: ambient context

I think the above solution with dependency injection, interfaces and decorators follows SOLID principles quite well. We can build upon the ProductService class using the decorators, pass different implementations of the abstractions and test each component independently.

As discussed in the post on Interception – check the section called Interception using the Decorator pattern – this solution can have some practical limitations, such as writing a large number of tedious code. While you may not want to do caching in every single layer, logging is different. You may want to log from just about any layer of the application: UI, services, controllers, repositories. So you may need to write a LoggedController, LoggedRepository, LoggedService etc. for any component where you want to introduce logging.

In the post on patterns in dependency injection we discussed a technique called ambient context. I suggest you read that section if you don’t understand the term otherwise you may not understand the purpose of the code below. Also, you’ll find its advantages and disadvantages there as well.

Insert the following class into the Logging folder of the infrastructure project:

public abstract class LogProviderContext
{
	private static readonly string _nameDataSlot = "LogProvider";

	public static ILoggingService Current
	{
		get
		{
			ILoggingService logProviderContext = Thread.GetData(Thread.GetNamedDataSlot(_nameDataSlot)) as ILoggingService;
			if (logProviderContext == null)
			{
				logProviderContext = LogProviderContext.DefaultLogProviderContext;
				Thread.SetData(Thread.GetNamedDataSlot(_nameDataSlot), logProviderContext);
			}
			return logProviderContext;
		}
		set
		{
			Thread.SetData(Thread.GetNamedDataSlot(_nameDataSlot), value);
		}
	}

	public static ILoggingService DefaultLogProviderContext = new ConsoleLoggingService();
}

You can call this code from any other layer which has a reference to the infrastructure layer. E.g. you can have the following code directly in ProductService.GetProducts:

LogProviderContext.Current.LogInfo(this, "Log message from the contextual log provider");

Solution 3: injecting logging into ProductService

Another solution which lies somewhere between ambient context and the decorator is having ProductService depend upon an ILoggingService:

public ProductService(IProductRepository productRepository, ILoggingService loggingService)

You can then use the injected ILoggingService to log you messages. We saw a similar example in the post on caching and also in the post on Interception referred to above. Read the section called Dependency injection in the post on Interception to read more why this approach might be good or bad.

However, if you’re faced with such a constructor and still want to test ProductService in isolation you can use a Null Object version of ILoggingService. Add the following class to the Logging folder:

public class NoLogService : ILoggingService
{
	public void LogInfo(object logSource, string message, Exception exception = null)
	{}

	public void LogWarning(object logSource, string message, Exception exception = null)
	{}

	public void LogError(object logSource, string message, Exception exception = null)
	{}

	public void LogFatal(object logSource, string message, Exception exception = null)
	{}
}

In the next post we’ll continue with logging to show a more realistic implementation of ILoggingService with log4net.

View the list of posts on Architecture and Patterns here.

Externalising dependencies with Dependency Injection in .NET part 3: configuration

Introduction

In the previous post of this series we looked at how to remove the caching logic from a class and hide it behind an interface. We’ll follow in a similar fashion in this post which takes up reading settings from a configuration source.

We’ll build upon the demo we’ve been working on so far so have it ready in Visual Studio.

Configuration and settings

Probably every even vaguely serious application out there has some configuration store. The configuration values contain the settings that are necessary so that the app can function normally. A good example from .NET is the web.config or app.config file with their appSettings section:

<appSettings>
    <add key="Environment" value="Alpha" />
    <add key="MinimumLimit" value="1000" />
    <add key="Storage" value="mongo" />
</appSettings>

In Java you’d put these settings into a .properties file. The configuration files will allow you to change the behaviour of your app without recompiling and redeploying them.

You can of course store your settings in other sources: a database, a web service or some other mechanism. Hence the motivations for hiding the concrete technology behind an abstraction are similar to those listed in the post on caching: testability, flexibility, SOLID.

The abstraction

Application settings are generally key-value pairs so constructing an interface for a settings storage is fairly simple and the below example is one option. The key is almost always a string and the value can be any primitive or a string. Add a new folder called Configuration to the infrastructure layer. Add the following interface to it:

public interface IConfigurationRepository
{
	T GetConfigurationValue<T>(string key);
	T GetConfigurationValue<T>(string key, T defaultValue);
}

The implementation

One obvious implementation is to read the values from app.config/web.config using the ConfigurationManager class in the System.Configuration library. Add this dll to the references list of the infrastructure layer.

Then insert the following implementation of the interface to the Configuration folder:

public class ConfigFileConfigurationRepository : IConfigurationRepository
{
	public T GetConfigurationValue<T>(string key)
	{
		string value = ConfigurationManager.AppSettings[key];
		if (value == null)
		{
			throw new KeyNotFoundException("Key " + key + " not found.");
		}
		try
		{
			if (typeof(Enum).IsAssignableFrom(typeof(T)))
				return (T)Enum.Parse(typeof(T), value);
			return (T)Convert.ChangeType(value, typeof(T));
		}
		catch (Exception ex)
		{
			throw ex;
		}
	}

	public T GetConfigurationValue<T>(string key, T defaultValue)
	{
		string value = ConfigurationManager.AppSettings[key];
		if (value == null)
		{
			return defaultValue;
		}
		try
		{
			if (typeof(Enum).IsAssignableFrom(typeof(T)))
				return (T)Enum.Parse(typeof(T), value);
			return (T)Convert.ChangeType(value, typeof(T));
		}
		catch (Exception ex)
		{
			return defaultValue;
        	}
	}
}

The console app has an app.config file by default. If not then you’ll need to add an Application Configuration File as it’s called in the Add New Item dialog. We’ll simulate a test scenario where it’s possible to return a default product instead of consulting the data store. Add the following appSettings section with the configuration tags of app.config:

<appSettings>
	<add key="returnDefaultProduct" value="true"/>
	<add key="defaultProductId" value="99"/>
	<add key="defaultProductName" value="DEFAULT"/>
	<add key="defaultProductQuantity" value="1000"/>
</appSettings>

Next we’ll inject the dependency through the constructor of ProductService. Modify the ProductService private fields and constructor as follows:

private readonly IProductRepository _productRepository;
private readonly IConfigurationRepository _configurationRepository;

public ProductService(IProductRepository productRepository, IConfigurationRepository configurationRepository)
{
	if (productRepository == null) throw new ArgumentNullException("ProductRepository");
	if (configurationRepository == null) throw new ArgumentNullException("ConfigurationRepository");
	_productRepository = productRepository;
	_configurationRepository = configurationRepository;
}

This breaks of course the existing code which constructs a ProductService. Modify it as follows:

IProductService productService = new ProductService(new ProductRepository(), new ConfigFileConfigurationRepository());

The modify ProductService.GetProduct as follows to use the configuration repository:

public GetProductResponse GetProduct(GetProductRequest getProductRequest)
{
	GetProductResponse response = new GetProductResponse();
	try
	{
		bool returnDefault = _configurationRepository.GetConfigurationValue<bool>("returnDefaultProduct", false);
		Product p = returnDefault ? BuildDefaultProduct() : _productRepository.FindBy(getProductRequest.Id);
		response.Product = p;
		if (p != null)
		{
			response.Success = true;
		}
		else
		{
			response.Exception = "No such product.";
		}
	}
	catch (Exception ex)
	{
		response.Exception = ex.Message;
	}
	return response;
}

private Product BuildDefaultProduct()
{
	Product defaultProduct = new Product();
	defaultProduct.Id = _configurationRepository.GetConfigurationValue<int>("defaultProductId");
	defaultProduct.Name = _configurationRepository.GetConfigurationValue<string>("defaultProductName");
	defaultProduct.OnStock = _configurationRepository.GetConfigurationValue<int>("defaultProductQuantity");
	return defaultProduct;
}

Run Main and you’ll see that the configuration values are indeed correctly retrieved from app.config. A possible improvement here is to put all configuration keys into a separate container class or a resource file instead of putting them here directly. Then you could retrieve them by writing something like this:

defaultProduct.Id = _configurationRepository.GetConfigurationValue<int>(ConfigurationKeys.DefaultProductId);

In the next post we’ll look at logging.

View the list of posts on Architecture and Patterns here.

Externalising dependencies with Dependency Injection in .NET part 2: caching

Introduction

In the previous post we set up the startup project for our real discussion. In this post we’ll take a look at caching as a dependency.

Adding caching

Our glorious application is a success and grows by an incredible rate every month. It starts getting slow and the users keep complaining about the performance. The team decides to add caching to the service layer: cache the result of the “product by id” query to the repository for some time. The team decides to make this quick and modifies the GetProduct method as follows:

public GetProductResponse GetProduct(GetProductRequest getProductRequest)
{
	GetProductResponse response = new GetProductResponse();
	try
	{
		string storageKey = "GetProductById";
		ObjectCache cache = MemoryCache.Default;
		Product p = cache.Contains(storageKey) ? (Product)cache[storageKey] : null;
		if (p == null)
		{
			p = _productRepository.FindBy(getProductRequest.Id);
			CacheItemPolicy policy = new CacheItemPolicy() { AbsoluteExpiration = DateTime.Now.AddMinutes(5) };
			cache.Add(storageKey, p, policy);
		}
		response.Product = p;
		if (p != null)
		{
			response.Success = true;
		}
		else
		{
			response.Exception = "No such product.";
		}
	}
	catch (Exception ex)
	{
		response.Exception = ex.Message;
	}
	return response;
}

You’ll need to set a reference to the System.Runtime.Caching dll to find the ObjectCache object.

So we cache the product search result for 5 minutes. In order to see this in action add a second call to the the product service just above Console.ReadKey() in Main:

getProductResponse = productService.GetProduct(new GetProductRequest() { Id = 2 });

I encourage you to step through the code with F11. You’ll see that the first productService.GetProduct retrieves the product from the repository and adds the item to the cache. The second call fetches the product from the cache.

What’s wrong with this?

The code works, so where’s the problem?

Testability

The method is difficult to test in isolation because of the dependency on the ObjectCache class. The actual purpose of the method is to get a product by ID. However, if the code also caches the result then it’s difficult to test the result from GetProduct. If you want to get any reliable result from the test that tests the behaviour of this method you’ll need to somehow flush the cache before every test so that you know that got a fresh result, not a cached one. Otherwise if the test fails, then why did it fail? Was it a genuine failure, meaning that the product was not retrieved? Or was it because the caching mechanism failed? It’s the wrong approach making the test outcome dependent on such a dependency.

Flexibility

With this implementation we’re stuck with the ObjectContext as our caching solution. What if we want to change over to a different one, such as Memcached or HttpContext? In that case we’d need to go in and manually replace the ObjectCache solution to a new one. Even worse, let’s say all your service classes use ObjectCache for caching and you want to make the transition to another caching solution for all of them. You probably see how tedious, time consuming and error-prone this could be.

Single responsibility

The method also violates the Single Responsibility Principle as it performs caching in its method body. Strictly speaking it should not be doing this as it then introduces a hidden side effect. The caller of the method doesn’t know that the result is cached and may be surprised to see an outdated product if it’s e.g. updated directly in the database.

The solution will involve 2 patterns:

  • Adapter: to factor out the caching strategy behind an abstraction. We used caching to demonstrate the Adapter pattern and much of it will be re-used here.
  • Decorator: to completely break out the caching code from ProductService and put it in an encasing class

Step 1: hide caching

This is where we need to consider the operations expected from any caching engine. We should be able to store, retrieve and delete objects using any cache engine, right? Those operations should be common to all caching implementations.

As caching is a cross-cutting concern we’ll start building our infrastructure layer. Add a new C# class library called MyCompany.Infrastructure.Common to the solution and insert a new folder called Caching. Add the following interface to the Caching folder:

public interface ICacheStorage
{
	void Remove(string key);
	void Store(string key, object data);
	void Store(string key, object data, DateTime absoluteExpiration, TimeSpan slidingExpiration);
	T Retrieve<T>(string key);
}

Any decent caching engine should be able to fulfil this interface. Add the following implementation to the same folder. The implementation uses ObjectCache:

public class SystemRuntimeCacheStorage : ICacheStorage
{
	public void Remove(string key)
	{
		ObjectCache cache = MemoryCache.Default;
		cache.Remove(key);
	}

	public void Store(string key, object data)
	{
		ObjectCache cache = MemoryCache.Default;
		cache.Add(key, data, null);
	}

	public void Store(string key, object data, DateTime absoluteExpiration, TimeSpan slidingExpiration)
	{
		ObjectCache cache = MemoryCache.Default;
		var policy = new CacheItemPolicy
		{
			AbsoluteExpiration = absoluteExpiration,
			SlidingExpiration = slidingExpiration
		};

		if (cache.Contains(key))
		{
			cache.Remove(key);
		}

		cache.Add(key, data, policy);
	}
		
	public T Retrieve<T>(string key)
	{
		ObjectCache cache = MemoryCache.Default;
		return cache.Contains(key) ? (T) cache[key] : default(T);
	}
}

You’ll need to add a reference to the System.Runtime.Caching dll in the infrastructure layer as well. ObjectCache is an all-purpose cache which works with pretty much any .NET project type. However, say you’d like to go for an HttpContext cache then you can have the following implementation:

public class HttpContextCacheStorage : ICacheStorage
{
	public void Remove(string key)
	{
		HttpContext.Current.Cache.Remove(key);
	}

	public void Store(string key, object data)
	{
		HttpContext.Current.Cache.Insert(key, data);
	}

	public void Store(string key, object data, DateTime absoluteExpiration, TimeSpan slidingExpiration)
	{
		HttpContext.Current.Cache.Insert(key, data, null, absoluteExpiration, slidingExpiration);
	}

	public T Retrieve<T>(string key)
	{
		T itemStored = (T)HttpContext.Current.Cache.Get(key);
		if (itemStored == null)
			itemStored = default(T);

		return itemStored;
	}
}

We’ll need to be able to inject our caching implementation to the product service and not let the product service determine which strategy to take. In that case the implementation is still hidden to the caller and we still have a hard dependency on one of the concrete implementations. The revised ProductService looks as follows:

public class ProductService : IProductService
{
	private readonly IProductRepository _productRepository;
	private readonly ICacheStorage _cacheStorage;

	public ProductService(IProductRepository productRepository, ICacheStorage cacheStorage)
	{
		if (productRepository == null) throw new ArgumentNullException("ProductRepository");
		if (cacheStorage == null) throw new ArgumentNullException("CacheStorage");
		_productRepository = productRepository;
		_cacheStorage = cacheStorage;
	}

	public GetProductResponse GetProduct(GetProductRequest getProductRequest)
	{
		GetProductResponse response = new GetProductResponse();
		try
		{
			string storageKey = "GetProductById";
			Product p = _cacheStorage.Retrieve<Product>(storageKey);
			if (p == null)
			{
				p = _productRepository.FindBy(getProductRequest.Id);
				_cacheStorage.Store(storageKey, p, DateTime.Now.AddMinutes(5), TimeSpan.Zero);
					
			}
			response.Product = p;
			if (p != null)
			{
				response.Success = true;
			}
			else
			{
				response.Exception = "No such product.";
			}
		}
		catch (Exception ex)
		{
			response.Exception = ex.Message;
		}
		return response;
	}
}

You’ll need to add a reference to the infrastructure layer from the console.

We’ve successfully got rid of the ObjectCache dependency. You can even remove the System.Runtime.Caching dll from the references list in the Console layer. The ProductService creation code in Main is modified as follows:

IProductService productService = new ProductService(new ProductRepository(), new SystemRuntimeCacheStorage());

Run the code and you’ll see that it still works. Now ProductService is oblivious of the concrete implementation of ICacheStorage and you’re free to change it in the caller. You can then change the caching mechanism for all your caching needs by changing the concrete implementation of ICacheStorage.

Step 2: removing caching altogether

As it currently stands the GetProduct method still violates ‘S‘ in SOLID, i.e. the Single Responsibility Principle. The purpose of GetProduct is to retrieve a product from the injected repository, it has nothing to do with caching. The constructor signature at least indicates to the caller that there’s caching going on – the caller must send an ICacheStorage implementation – but testing the true purpose of GetProduct is still not straightforward.

Luckily we have the Decorator pattern hinted at above to solve the problem. I’ll not go into the details of the pattern here, you can read about it in great detail under the link provided. In short it helps to augment the functionality of a class in an object-oriented manner by building an encasing, “enriched” version of the class. That’s exactly what we’d like to build: augment the plain ProductService class with caching. Let’s see what this could look like.

The Decorator pattern has a couple of different implementations, here’s one variant. Add the following implementation of IProductService into the Services folder:

public class CachedProductService : IProductService
{
	private readonly IProductService _productService;
	private readonly ICacheStorage _cacheStorage;

	public CachedProductService(IProductService productService, ICacheStorage cacheStorage)
	{
		if (productService == null) throw new ArgumentNullException("ProductService");
		if (cacheStorage == null) throw new ArgumentNullException("CacheStorage");
		_cacheStorage = cacheStorage;
		_productService = productService;
	}

	public GetProductResponse GetProduct(GetProductRequest getProductRequest)
	{
		GetProductResponse response = new GetProductResponse();
		try
		{
			string storageKey = "GetProductById";
			Product p = _cacheStorage.Retrieve<Product>(storageKey);
			if (p == null)
			{
				response = _productService.GetProduct(getProductRequest);
				_cacheStorage.Store(storageKey, response.Product, DateTime.Now.AddMinutes(5), TimeSpan.Zero);
			}
                        else
			{
				response.Success = true;
				response.Product = p;
			}
		}
		catch (Exception ex)
		{
			response.Exception = ex.Message;
		}
		return response;
	}
}

We delegate both the product retrieval and the caching to the injected implementations of the abstractions.

ProductService.cs can be changed back to its original form:

public class ProductService : IProductService
{
	private readonly IProductRepository _productRepository;

	public ProductService(IProductRepository productRepository)
	{
		if (productRepository == null) throw new ArgumentNullException("ProductRepository");
		_productRepository = productRepository;
	}

	public GetProductResponse GetProduct(GetProductRequest getProductRequest)
	{
		GetProductResponse response = new GetProductResponse();
		try
		{
			Product p = _productRepository.FindBy(getProductRequest.Id);
			response.Product = p;
			if (p != null)
			{
				response.Success = true;
			}
			else
			{
				response.Exception = "No such product.";
			}
		}
		catch (Exception ex)
		{
			response.Exception = ex.Message;
		}
		return response;
	}
}

The calling code in Main will look as follows:

static void Main(string[] args)
{
	IProductService productService = new ProductService(new ProductRepository());
	IProductService cachedProductService = new CachedProductService(productService, new SystemRuntimeCacheStorage());
	GetProductResponse getProductResponse = cachedProductService.GetProduct(new GetProductRequest() { Id = 2 });
	if (getProductResponse.Success)
	{
		Console.WriteLine(string.Concat("Product name: ", getProductResponse.Product.Name));
	}
	else
	{
		Console.WriteLine(getProductResponse.Exception);
	}

	getProductResponse = cachedProductService.GetProduct(new GetProductRequest() { Id = 2 });

	Console.ReadKey();
}

Note how we first create a ProductService which is then injected into the CachedProductService along with the selected caching strategy.

So now ProductService can be tested in isolation.

Plan B: Null object caching

You are not always in control of all parts of the source code. In other cases changing ProductService like that may cause a long delay in development time due to tightly coupled code. So imagine that you have to use a product service like we had after step 1:

public ProductService(IProductRepository productRepository, ICacheStorage cacheStorage)

So you have to inject a caching strategy but still want to test the true purpose of GetMessage, i.e. bypass caching altogether. The Null Object pattern comes to the rescue. So we create a dummy implementation of ICacheStorage that doesn’t do anything. Add the following implementation into the Caching folder of the infrastructure layer:

public class NoCacheStorage : ICacheStorage
{
	public void Remove(string key)
	{}

	public void Store(string key, object data)
	{}

	public void Store(string key, object data, DateTime absoluteExpiration, TimeSpan slidingExpiration)
	{}

	public T Retrieve<T>(string key)
	{
		return default(T);
	}
}

You can inject this dummy implementation to ProductService to eliminate all caching:

IProductService productService = new ProductService(new ProductRepository(), new NoCacheStorage());

In the next post we’ll look at how to hide reading from a configuration file.

View the list of posts on Architecture and Patterns here.

Externalising dependencies with Dependency Injection in .NET part 1: setup

Introduction

Earlier on this blog we talked a lot about concepts like SOLID, patterns and layered software architecture using Domain Driven Design.

This new series of 10 posts will draw a lot on those ideas. Here are the main goals:

  • Show how hard dependencies of an object can be made external by hiding them behind abstractions
  • Show the reasons why you should care about those dependencies
  • Build a common infrastructure layer that you can use in your own projects

What is an infrastructure layer? We saw an example of that in this post. It is a special layer in the software architecture that holds the code which is common to all other layers in the project. This is a collection of cross-cutting concerns, like caching, security, emailing, logging etc. Logging is seldom part of any company domain but you may want to log trace messages from the “main” layers of the project: the service, the UI and the repository layer. It’s not too clever to replicate the logging code in each layer. Instead, break it out to a separate infrastructure layer which is typically a C# library project.

Furthermore, it’s possible that you’ll want to follow the same logging technique and strategy across all projects of your company. Then you can have one central infrastructure layer which all projects refer to from within Visual Studio. Then if the developers decide to change the logging, caching or other strategy then it will change across all projects by modifying this one central infrastructure layer.

In this post we’ll set up a very simple starting point that lays the foundations for the upcoming parts in the series.

Starting point

Open Visual Studio 2012/2013 and create a new Blank Solution, call it CommonInfrastructureDemo. Add a new Console Application to it called MyCompany.ProductConsole. Add 3 new folders to the ProductConsole app called Domains, Services, Repositories.

Normally we’d put these elements into separate C# libraries but it’s not the main focus of this series. If you’re interested in layered software architecture then you can find a proposed way of achieving it in the DDD series referred to above.

We’ll have only one domain: Product. Add a C# class called Product to the Domains folder:

public class Product
{
	public int Id { get; set; }
	public string Name { get; set; }
	public int OnStock { get; set; }
}

Also, add the following repository interface to the Domains folder:

public interface IProductRepository
{
	Product FindBy(int id);
}

Add the following implementation of the repository to the Repositories folder:

public class ProductRepository : IProductRepository
{
	public Product FindBy(int id)
	{
		return (from p in AllProducts() where p.Id == id select p).FirstOrDefault();
	}

	private IEnumerable<Product> AllProducts()
	{
		return new List<Product>()
		{
			new Product(){Id = 1, Name = "Chair", OnStock = 10}
			, new Product(){Id = 2, Name = "Desk", OnStock = 20}
			, new Product(){Id = 3, Name = "Cupboard", OnStock = 15}
		};
	}
}

There’s nothing really magical here I guess.

Normally the ultimate consumer layer, such as an MVC or Web API layer with a number of controllers, will not talk directly to the repositories. It will only consult the services for any data retrieval. Add the following interface to the Services folder:

public interface IProductService
{
	GetProductResponse GetProduct(GetProductRequest getProductRequest);
}

…where GetProductResponse and GetProductRequest also reside in the Services folder and look as follows:

public class GetProductRequest
{
	public int Id { get; set; }
}

public class GetProductResponse
{
	public bool Success { get; set; }
	public string Exception { get; set; }
	public Product Product { get; set; }
}

The implementation of IProductService will need an IProductRepository. We’ll let this dependency to be injected into the product service using constructor injection. Insert the following ProductService class into the Services folder:

public class ProductService : IProductService
{
	private readonly IProductRepository _productRepository;

	public ProductService(IProductRepository productRepository)
	{
		if (productRepository == null) throw new ArgumentNullException("ProductRepository");
		_productRepository = productRepository;
	}

	public GetProductResponse GetProduct(GetProductRequest getProductRequest)
	{
		GetProductResponse response = new GetProductResponse();
		try
		{
			Product p = _productRepository.FindBy(getProductRequest.Id);
			response.Product = p;
			if (p != null)
			{
				response.Success = true;
			}
			else
			{
				response.Exception = "No such product.";
			}
		}
		catch (Exception ex)
		{
			response.Exception = ex.Message;
		}
		return response;
	}
}

In the implemented GetProduct method we ask the repository to return a Product. If none’s found or if the operation throws an exception then we let the Success property be false and populate the exception message accordingly.

We can now tie together all elements in the consumer, i.e. the Main method. We won’t employ any Inversion of Control containers to inject our dependencies so that we don’t get distracted by technical details. Instead we’ll do it the old way, i.e. by poor man’s dependency injection. We define the concrete implementations in Main ourselves. However, it’s an acceptable solution as this definition happens right at the entry point of the application. If you don’t know what I mean I suggest you go through the series on SOLID referred to above with special attention to the letter ‘D‘.

With the above remarks in mind add the following code into Main in Program.cs:

static void Main(string[] args)
{
	IProductService productService = new ProductService(new ProductRepository());
	GetProductResponse getProductResponse = productService.GetProduct(new GetProductRequest() { Id = 2 });
	if (getProductResponse.Success)
	{
		Console.WriteLine(string.Concat("Product name: ", getProductResponse.Product.Name));
	}
	else
	{
		Console.WriteLine(getProductResponse.Exception);
	}

	Console.ReadKey();
}

Run the app and you’ll see that the Console prints “Desk” for us. Test the code with Id = 4 and you’ll see the appropriate exception message: “No such product”.

This finishes the project setup phase. In the next post we’ll start discussing the true purpose of this series with a look at caching in the service layer.

View the list of posts on Architecture and Patterns here.

Extension to the DDD skeleton project: per session object context in Repository layer

Introduction

If you followed through the DDD skeleton project blog series then you’ll recall that the following interface was used to get hold of the DB object context in the concrete repositories:

public interface IObjectContextFactory
{
	InMemoryDatabaseObjectContext Create();
}

You’ll also recall that we pulled a valid InMemoryDatabaseObjectContext instance using the singleton pattern:

public class LazySingletonObjectContextFactory : IObjectContextFactory
{
	public InMemoryDatabaseObjectContext Create()
	{
		return InMemoryDatabaseObjectContext.Instance;
	}
}

In retrospect I think I should have gone through another implementation of the IObjectContextFactory interface, one that better suits a real life scenario with an ORM platform such as Entity Framework or NHibernate.

If you’d like to take on the singleton pattern to construct and retrieve an EF object context then you’ll likely run into some difficulties. The singleton pattern was OK for this in-memory solution so that we could demonstrate insertions, deletions and updates in the repository. As the singleton always returns the same InMemoryDatabaseObjectContext instance we won’t lose the new data from request to request as we saw in the demo.

However, this is not desirable if you’re working with an EF object context. If you always return the same object context for every request then even the data retrieved by that object context will be the same upon subsequent requests. If you make a change to an object then it won’t be visible in another session as that new session retrieves the same object context that was present when it was created by the singleton, i.e. when it was first called:

public static InMemoryDatabaseObjectContext Instance
{
	get
	{
		return Nested.instance;
	}
}

private class Nested
{
	static Nested()
	{
	}
	internal static readonly InMemoryDatabaseObjectContext instance = new InMemoryDatabaseObjectContext();
}

If you update a Customer object in one session then the next session won’t see the updates as it still retrieves the original, “unchanged” Customer that was present in the original instance of InMemoryDatabaseObjectContext. You’ll need to call the Refresh method of the EF object context manually to make sure that you get the latest state of the retrieved object like this:

Customer c = some query;
if (c != null)
{
	EfObjectContextInstance.Refresh(RefreshMode.StoreWins, c);
}

In short: my recommendation is that you don’t use the singleton pattern to retrieve the EF object context.

An EntityFramework friendly solution

A better solution is to get an instance of the object context per HTTP session. This requires a different implementation of the IObjectContextFactory interface. The following implementation can do the job:

public class HttpAwareOrmDataContextFactory : IObjectContextFactory
{
	private string _dataContextKey = "EfObjectContext";

	public InMemoryDatabaseObjectContext Create()
	{
		InMemoryDatabaseObjectContext objectContext = null;
		if (HttpContext.Current.Items.Contains(_dataContextKey))
		{
			objectContext = HttpContext.Current.Items[_dataContextKey] as InMemoryDatabaseObjectContext;
		}
		else
		{
			objectContext = new InMemoryDatabaseObjectContext();
			Store(objectContext);
		}
		return objectContext;
	}

	private void Store(InMemoryDatabaseObjectContext objectContext)
	{
		if (HttpContext.Current.Items.Contains(_dataContextKey))
		{
			HttpContext.Current.Items[_dataContextKey] = objectContext;
		}
		else
		{
			HttpContext.Current.Items.Add(_dataContextKey, objectContext);
		}
	}
}

We use the IDictionary object of HttpContext.Current.Items to store the InMemoryDatabaseObjectContext instance. We first check if an instance is available by the key _dataContextKey. If that’s the case then we return that instance. Otherwise we create a new instance of the object context and store it in the dictionary. HttpContext.Current will of course always be different with each new HTTP request to the API which ensures that we get the fresh data from the data store as well. In case the InMemoryDatabaseObjectContext is requested more than once during the same session then we hand out the same instance.

You might ask why we don’t construct a new InMemoryDatabaseObjectContext every single time one is needed like this:

public InMemoryDatabaseObjectContext Create()
{
     return new InMemoryDatabaseObjectContext();
}

That wouldn’t be a good idea as the object context will be called when making some changes to the underlying DB objects and then it’s called again when the changes are to be persisted using two separate calls to the Unit of Work:

void RegisterUpdate(IAggregateRoot aggregateRoot, IUnitOfWorkRepository repository);
.
.
.
void Commit();

The two calls will be very likely made during the same session otherwise the changes are lost. If you construct an InMemoryDatabaseObjectContext to register the changes and then construct another one to commit them then the second instance won’t automatically track the same updates of course so it won’t persist anything. That’s logical as we’re talking about two different instances: how would object context instance #2 know about the changes tracked by object context instance #1?

So now we have two implementations of the IObjectContextFactory interface. The beauty with our loosely coupled solution is that all it takes to change the concrete implementation injected into all Repository classes is to comment out the following line of code in IoC.cs:

x.For<IObjectContextFactory>().Use<LazySingletonObjectContextFactory>();

…and insert the following instead:

x.For<IObjectContextFactory>().Use<HttpAwareOrmDataContextFactory>();

You can run the project as it is now. Navigate to /customers and you should get the same dummy 3 customers we saw in the original demo.

View the list of posts on Architecture and Patterns here.

Extension to the DDD skeleton project: using an external settings source

Introduction

In this post we saw a way how to introduce caching in the DDD project. We also mentioned that hardcoding the caching duration directly in code may not be desirable for testing and maintenance purposes.

One way to externalise the caching duration is the following setup:

  • We can have a settings file where we set up the caching profiles, such as LongCache = 1 minute, MediumCache = 30sec, ShortCache = 10sec.
  • These profiles can be saved in different places: web.config or app.config, database, customised XML/JSON file, even an external service
  • This is telling us that retrieving the correct setting should be abstracted away

Infrastructure

Open the Infrastructure.Common layer and insert a new folder called Configuration. Insert the following interface:

public interface IConfigurationRepository
{        	
        T GetConfigurationValue<T>(string key);
        string GetConfigurationValue(string key);
        T GetConfigurationValue<T>(string key, T defaultValue);
        string GetConfigurationValue(string key, string defaultValue);
}

We’ll go for the most obvious implementation: the appSettings section in web.config. Insert the following class into the folder:

public class AppSettingsConfigurationRepository : IConfigurationRepository
{        
        public T GetConfigurationValue<T>(string key)
        {
            return GetConfigurationValue(key, default(T), true);
        }

        public string GetConfigurationValue(string key)
        {
            return GetConfigurationValue<string>(key);
        }

        public T GetConfigurationValue<T>(string key, T defaultValue)
        {
            return GetConfigurationValue(key, defaultValue, false);
        }
        
        public string GetConfigurationValue(string key, string defaultValue)
        {
            return GetConfigurationValue<string>(key, defaultValue);
        }

        private T GetConfigurationValue<T>(string key, T defaultValue, bool throwException)
        {
            var value = ConfigurationManager.AppSettings[key];
            if (value == null)
            {
                if(throwException)
                    throw new KeyNotFoundException("Key "+key+ " not found.");
                return defaultValue;
            }
            try
            {
                if (typeof(Enum).IsAssignableFrom(typeof(T)))
                    return (T)Enum.Parse(typeof(T), value);
                return (T)Convert.ChangeType(value, typeof(T));
            }
            catch (Exception ex)
            {
                if (throwException)
                    throw ex;
                return defaultValue;
            }
        }
}

You’ll need to set a reference to the System.Configuration library otherwise ConfigurationManager will not be found.

This is an application of the Adapter pattern which we used in the previous post.

Application service

Locate the EnrichedCustomerService class from the previous post on Service layer caching. Add the following private field:

private readonly IConfigurationRepository _configurationRepository;

Modify the constructor as follows:

public EnrichedCustomerService(ICustomerService innerCustomerService, ICacheStorage cacheStorage, IConfigurationRepository configurationRepository)
{
	if (innerCustomerService == null) throw new ArgumentNullException("CustomerService");
	if (cacheStorage == null) throw new ArgumentNullException("CacheStorage");
	if (configurationRepository == null) throw new ArgumentNullException("ConfigurationRepository");
	_innerCustomerService = innerCustomerService;
	_cacheStorage = cacheStorage;
	_configurationRepository = configurationRepository;
}

We want to read the cache duration setting in GetAllCustomers. Modify the method as follows:

public GetCustomersResponse GetAllCustomers()
{
	string key = "GetAllCustomers";
	GetCustomersResponse response = _cacheStorage.Retrieve<GetCustomersResponse>(key);
	if (response == null)
	{
		int cacheDurationSeconds = _configurationRepository.GetConfigurationValue<int>("ShortCacheDuration");
		response = _innerCustomerService.GetAllCustomers();
		_cacheStorage.Store(key, response, TimeSpan.FromSeconds(cacheDurationSeconds));
	}
	return response;
}

It would be better to have some external container for string values such as ShortCacheDuration, but this will be enough for now.

Web layer

Open the web.config file and enter the following appSetting:

<add key="ShortCacheDuration" value="60"/>

We also need to instruct StructureMap to select AppSettingsConfigurationRepository for any IConfigurationRepository it encounters. Enter the following line into the ObjectFactory.Initialize block of IoC.cs:

x.For<IConfigurationRepository>().Use<AppSettingsConfigurationRepository>();

Set a breakpoint within GetAllCustomers() of EnrichedCustomerService.cs. Set the start page to “customers”: open the Properties of the WebService layer, select Web, Specific Page, “customers”. Start the application.

Code execution will stop at the break point. Step through the code by pressing F11. You’ll see how the settings are extracted from the config file and used with the cache storage mechanism.

Now every time you want to change the cache duration you just update the appropriate settings value. There’s nothing stopping you from inserting different cache duration profiles in your configuration source as mentioned above: ShortCache, LongCache, MediumCache etc. Also, we solved yet another dependency problem in an OOP and SOLID way.

Read the next extension to the DDD project here.

View the list of posts on Architecture and Patterns here.

Extension to the DDD skeleton project: caching in the service layer

Introduction

This post is a direct continuation of the DDD skeleton project. In this extension we’ll investigate how to incorporate caching into the solution.

Caching can mean several things in an application. It can be introduced at different levels: you can cache database call results, MVC views, service call results, etc. You can save just about any object in one of the cache engines built into .NET.

In this post we’ll concentrate on caching in the Service layer. We’ll try to solve the requirement to cache the result of the following service call of ICustomerService for a period of time:

GetCustomersResponse GetAllCustomers();

A naive but quick solution would be to cache the results directly in the implementing CustomerService class:

public GetCustomersResponse GetAllCustomers()
{
        if (cacheEngine.IncludesObject<GetCustomersResponse>())
        {
              return cacheEngine.RetrieveObject<GetCustomersResponse>();
        }
        else
        {
	     GetCustomersResponse getCustomersResponse = new GetCustomersResponse();
	     IEnumerable<Customer> allCustomers = null;

	     try
	     {
		    allCustomers = _customerRepository.FindAll();
		    getCustomersResponse.Customers = allCustomers.ConvertToViewModels();
                    cacheEngine.SaveObject<GetCustomersResponse>(getCustomersResponse);
	     }
	     catch (Exception ex)
	     {
		    getCustomersResponse.Exception = ex;
	     }
	     return getCustomersResponse;
       }
}

There are a couple of problems with this solution:

  • The method violates the Single Responsibility Principle: it doesn’t only look up all customers but caches them as well
  • The method doesn’t indicate to its consumers what’s going in its method body. The signature states that it will retrieve all customers but there’s nothing about caching. If it returns stale data then the programmer must inspect the method body to find the reason – and will get a surprise: hey, you never told me about caching!
  • It’s difficult to test the service call in isolation: the cache is empty on the first test run but then as the method returns the cached data you cannot test the actual customer retrieval easily. You’d need to clear the cache before every test run. So if the test fails then you won’t know really why it fails: was it because the customer retrieval threw an exception or because the caching engine misbehaved?

Therefore a more thorough solution requires a different way of thinking.

If you are familiar with SOLID and especially the letter ‘D‘ then you’ll know that all this is pointing towards injecting the caching strategy into CustomerService without having to add the caching operations directly within the GetAllCustomers() method body.

There are different ways to solve this problem that we discussed in this post on Interception with their pros and cons:

  • The Decorator pattern
  • AOP
  • Dynamic interception with a DI container

In this post we’ll go for the “purist” Decorator pattern: it is very object oriented and is probably the easiest to follow for a newcomer to this topic. I’m not a fan of AOP – for reasons read the reference above – and dynamic interception is too technical at this level. I don’t want to make a very technical post concentrating on a specific DI container. We’ll learn a lot of new things with the Decorator pattern. In case you’re not at all familiar with the decorator pattern make sure to check out this reference. We’ll also see the Adapter pattern in action to hide the concrete implementation of the caching engine.

The solution we’re going to go through can be applied to a wide range of cross-cutting concerns, such as logging. I’ll present a decorator that adds caching to a service. By the same token you can build a decorator for logging as well. You can then decorate the service class with a logger AND a caching mechanism as well.

Infrastructure

Caching is an example of a cross-cutting concern. Caching can be introduced in many places within a solution and the same caching strategy can be re-used across several applications. This is pointing us towards the Infrastructure layer of the DDD skeleton project.

Also, the technology you choose for caching can vary: use one of the built-in objects in .NET, such as the System.Runtime.Cache, you can use a third part component or write your own custom solution. The point is that the caching engine may change and you’ll want to be able to easily change the concrete implementation. So it sounds like we have a variable dependency that may change over time, and therefore it needs to be hidden behind an abstraction.

Open the Infrastructure.Common layer of the DDD solution and add a new folder called Caching. Add the following interface:

public interface ICacheStorage
{
	void Remove(string key);
	void Store(string key, object data);
        void Store(string key, object data, TimeSpan slidingExpiration);
	void Store(string key, object data, DateTime absoluteExpiration, TimeSpan slidingExpiration);
	T Retrieve<T>(string key);
}

All cache storage mechanisms will need to implement this interface. We’ll go for the highly efficient, general-purpose caching engine of System.Runtime.Caching in the first implementation. Add the following class to the Caching folder:

public class SystemRuntimeCacheStorage : ICacheStorage
{
	public void Remove(string key)
	{
		ObjectCache cache = MemoryCache.Default;
		cache.Remove(key);
	}

	public void Store(string key, object data)
	{
		ObjectCache cache = MemoryCache.Default;
		cache.Add(key, data, null);
	}

	public void Store(string key, object data, DateTime absoluteExpiration, TimeSpan slidingExpiration)
	{
		ObjectCache cache = MemoryCache.Default;
		var policy = new CacheItemPolicy
		{
			AbsoluteExpiration = absoluteExpiration,
			SlidingExpiration = slidingExpiration
		};

		if (cache.Contains(key))
		{
			cache.Remove(key);
		}

		cache.Add(key, data, policy);
	}

	public T Retrieve<T>(string key)
	{
		ObjectCache cache = MemoryCache.Default;
		return cache.Contains(key) ? (T)cache[key] : default(T);
	}

        public void Store(string key, object data, TimeSpan slidingExpiration)
	{
		ObjectCache cache = MemoryCache.Default;
		var policy = new CacheItemPolicy
		{
			SlidingExpiration = slidingExpiration
		};

		if (cache.Contains(key))
		{
			cache.Remove(key);
		}

		cache.Add(key, data, policy);
	}
}

The code may not compile at first as ObjectCache is located in an unreferenced library. Add a reference to the System.Runtime.Caching dll in the Infrastructure project.

Decorator pattern in the ApplicationServices layer

OK, now we have the caching elements in place using the Adapter pattern. Next we want to enrich the existing CustomerService implementation of the ICustomerService interface to include caching. In the following stub we’ll delegate most of the methods to the inner customer service, which will be our “normal” CustomerService class – we’ll look at the GetAllCustomers() method in a sec. Insert the following class into the Implementations folder:

public class EnrichedCustomerService : ICustomerService
{
	private readonly ICustomerService _innerCustomerService;
	private readonly ICacheStorage _cacheStorage;

	public EnrichedCustomerService(ICustomerService innerCustomerService, ICacheStorage cacheStorage)		
	{
		if (innerCustomerService == null) throw new ArgumentNullException("CustomerService");
		if (cacheStorage == null) throw new ArgumentNullException("CacheStorage");
		_innerCustomerService = innerCustomerService;
		_cacheStorage = cacheStorage;
	}

	public GetCustomerResponse GetCustomer(GetCustomerRequest getCustomerRequest)
	{
		return _innerCustomerService.GetCustomer(getCustomerRequest);
	}

	public GetCustomersResponse GetAllCustomers()
	{
		throw new NotImplementedException();
	}

	public InsertCustomerResponse InsertCustomer(InsertCustomerRequest insertCustomerRequest)
	{
		return _innerCustomerService.InsertCustomer(insertCustomerRequest);
	}

	public UpdateCustomerResponse UpdateCustomer(UpdateCustomerRequest updateCustomerRequest)
	{
		return _innerCustomerService.UpdateCustomer(updateCustomerRequest);
	}

	public DeleteCustomerResponse DeleteCustomer(DeleteCustomerRequest deleteCustomerRequest)
	{
		return _innerCustomerService.DeleteCustomer(deleteCustomerRequest);
	}
}

Again, if you don’t understand the structure of this class check out the post on the Decorator pattern. Here’s the implementation of the GetAllCustomers() method:

public GetCustomersResponse GetAllCustomers()
{
	string key = "GetAllCustomers";
	GetCustomersResponse response = _cacheStorage.Retrieve<GetCustomersResponse>(key);
	if (response == null)
	{
		response = _innerCustomerService.GetAllCustomers();
		_cacheStorage.Store(key, response, TimeSpan.FromMinutes(1));
	}
	return response;
}

We check in the cache if a GetCustomersResponse object is present and return it. Otherwise we ask the inner customer service to fetch all customers and put the result into the cache for 1 minute – we’ll come back to this point at the end of the post.

We are done with the decorated CustomerService class. Now we’d like to make sure that the CustomerController receives the EnrichedCustomerService instead of CustomerService.

StructureMap

Recall that we’re using StructureMap as our DI container. At present it follows the convention that whenever it sees an interface dependency whose name starts with “I” it will look for a concrete implementation with the same name without the “I”: IProductService == ProcuctService, ICustomerRepository == CustomerRepository. We also saw examples of specifying a concrete class that StructureMap will insert:

x.For<IUnitOfWork>().Use<InMemoryUnitOfWork>();
x.For<IObjectContextFactory>().Use<LazySingletonObjectContextFactory>();

So we should be able to add the following code, right?

x.For<ICustomerService>().Use<EnhancedCustomerService>();

Keep in mind that EnhancedCustomerService also has a dependency on ICustomerService so this code would inject another EnhancedCustomerService into EnhancedCustomerService which is not what we want. The goal is the following:

  • The CustomerController class should get EnhancedCustomerService from StructureMap
  • EnhancedCustomerService should get CustomerService from StructureMap

In fact this is such a common problem that it has been solved multiple times in StructureMap. All decent DI containers provide a solution for the Decorator pattern. It can be solved in at least 3 ways in StructureMap:

  • Decorating with instance references
  • Decorating with named instances
  • Decorating with delegates

This is not a technical post about StructureMap so I won’t go into any detail. We’ll go for the first option. Locate the IoC.cs class in the WebService layer and add the the following piece of code the the ObjectFactory.Initialize block:

x.For<ICacheStorage>().Use<SystemRuntimeCacheStorage>();
var customerService = x.For<ICustomerService>().Use<CustomerService>();
x.For<ICustomerService>().Use<EnrichedCustomerService>().Ctor<ICustomerService>().Is(customerService);

The first row is quite clear: we want to use the SystemRuntimeCacheStorage implementation of the ICacheStorage interface. The second row indicates that we want to use CustomerService where ICustomerService is used and retain a reference to the object returned by the Use method: a SmartInstance of T which is a StructureMap object. In the third row we modify this statement by saying that for ICustomerService we want an EnrichedCustomerService object and inject the retained customerService in its constructor. The other elements in the EnrichedCustomerService constructor will be resolved automatically by StructureMap. This looks a bit cryptic at first but that’s how it’s done, period.

Open the Properties window of the WebService layer, select the Web tag, click “Specific Page” and enter “customers” as the start-up page. Set a couple of breakpoints:

  • One withing the Get() method of CustomersController
  • Another one within GetAllCustomers() of EnrichedCustomerService

Start the web service and the start up URL in the browser should be something like http://localhost:9985/customers. The port number will probably be different in your case. Code execution should stop at the first breakpoint in the Get() method. Inspect the type of the injected ICustomerService in CustomersController.cs, it should be of type EnrichedCustomerService. Let the code continue and execution will stop again at GetAllCustomers in EnrichedCustomerService. Inspect the type of the inner customer service in that class: it should be of CustomerService. From here on I encourage you to step through the code with F11 to see how caching is used. Then refresh the page in the browser and you’ll see that the GetCustomersResponse is fetched from the cache instead of asking the CustomerService instance.

That’s about it. We have solved the caching problem in an object oriented, testable and SOLID way.

Further enhancement

There’s still room for improvement in our cache solution. Right now the cache duration is hard coded here:

_cacheStorage.Store(key, response, TimeSpan.FromMinutes(1));

It would be better with a more configurable solution where you can change the duration without coming back to this class every time. Imagine that you have caching in hundreds of classes – changing the duration in every single one will not make a happy programmer.

There are several ways to solve this problem. The next post will present a possible solution.

View the list of posts on Architecture and Patterns here.

Extension to the DDD skeleton project: domain specific rules Part 2

Introduction

In the first part of this DDD skeleton project extension we completed the domain and repository layers. The repository implementation was only a stub as we want to concentrate on validating domains with differing regional rules.

In this post we’ll finish off the communication chain in the skeleton web service.

Let’s get started! Open the DDD project and we’ll continue with the application service layer.

The Application services layer

We’ll concentrate on inserting new CountrySpecificCustomer objects in the data store. We won’t support the entire GET/POST/PUT/DELETE spectrum. You can do all that based on how we did it for the simple Customer object. Locate the Messaging folder and insert a new sub-folder called EnhancedCustomers. Insert the following messaging objects in this new folder:

public class CountrySpecificCustomerViewModel
{
	public string FirstName { get; set; }
	public int Age { get; set; }
	public string NickName { get; set; }
	public string Email { get; set; }
	public string CountryCode { get; set; }
}

public class InsertCountrySpecificCustomerRequest : ServiceRequestBase
{
	public CountrySpecificCustomerViewModel CountrySpecificCustomer { get; set; }
}

public class InsertCountrySpecificCustomerResponse : ServiceResponseBase
{}

Nothing fancy here I hope. These objects follow the same structure as their original Customer counterparts.

Add the following interface in the Interfaces folder:

public interface ICountrySpecificCustomerService
{
	InsertCountrySpecificCustomerResponse InsertCountrySpecificCustomer(InsertCountrySpecificCustomerRequest insertCustomerRequest);
}

Recall that the constructor of the CountrySpecificCustomer object is expecting an instance of Country. We already have a factory in the Domain layer that returns the correct country based on the country code. So we *could* use that factory here as well since the CountrySpecificCustomerViewModel allows for the specification of a country code. However, it would be unfortunate to use that concrete factory in the Services layer as it would only increase the degree of coupling between the Services and the Domain layer. So we’ll hide it behind an abstraction.

Locate the folder where you saved the CountryFactory object in the Domain layer. Insert the following interface:

public interface ICountryFactory
{
	Country CreateCountry(string countryCode);
}

The existing CountryFactory can implement the interface as follows:

public class CountryFactory : ICountryFactory
{
	private static IEnumerable<Country> AllCountries()
	{
		return new List<Country>() { new Hungary(), new Germany(), new Sweden() };
	}

	public static Country Create(string countryCode)
	{
		return (from c in AllCountries() where c.CountryCode.ToLower() == countryCode.ToLower() select c).FirstOrDefault();
	}

	public Country CreateCountry(string countryCode)
	{
		return Create(countryCode);
	}
}

Back in the services layer we can implement the ICountrySpecificCustomerService interface. Just to refresh our minds open the CustomerService class in the Implementations folder. You’ll recall that its constructor requires an IUnitOfWork object. The implementation of the ICountrySpecificCustomerService will also need one. This calls for a base class which both implementations can derive from. Insert the following abstract class in the Implementations folder:

public abstract class ApplicationServiceBase
{
	private readonly IUnitOfWork _unitOfWork;

	public ApplicationServiceBase(IUnitOfWork unitOfWork)
	{
		if (unitOfWork == null) throw new ArgumentNullException("UnitOfWork");
		_unitOfWork = unitOfWork;
	}

	public IUnitOfWork UnitOfWork
	{
		get
		{
			return _unitOfWork;
		}
	}
}

Next modify the declaration and constructor of the CustomerService object as follows:

public class CustomerService : ApplicationServiceBase, ICustomerService
{
	private readonly ICustomerRepository _customerRepository;

	public CustomerService(ICustomerRepository customerRepository, IUnitOfWork unitOfWork)
		: base(unitOfWork)
	{
		if (customerRepository == null) throw new ArgumentNullException("Customer repo");
		_customerRepository = customerRepository;
	}
.//implementations omitted
.
.
}

After this change you’ll get some errors saying that the _unitOfWork variable is not accessible, e.g. here:

_unitOfWork.Commit();

Replace those calls by referring to the public accessor of the base class:

UnitOfWork.Commit();

Add a new class to the Implementations folder called CountrySpecificCustomerService. Insert the following implementation stub:

public class CountrySpecificCustomerService : ApplicationServiceBase, ICountrySpecificCustomerService
{
	private readonly ICountrySpecificCustomerRepository _repository;
	private readonly ICountryFactory _countryFactory;

	public CountrySpecificCustomerService(IUnitOfWork unitOfWork, ICountrySpecificCustomerRepository repository
		, ICountryFactory countryFactory) : base(unitOfWork)
	{
		if (repository == null) throw new ArgumentNullException("CountrySpecificCustomerRepository");
		if (countryFactory == null) throw new ArgumentNullException("ICountryFactory");
		_repository = repository;
		_countryFactory = countryFactory;
	}

	public InsertCountrySpecificCustomerResponse InsertCountrySpecificCustomer(InsertCountrySpecificCustomerRequest insertCustomerRequest)
	{
		throw new NotImplementedException();
	}
}

In the InsertCountrySpecificCustomer implementation we’ll follow the same structure as in CustomerService.InsertCustomer: construct the domain object, validate it and then insert it. Insert the following implementation:

public InsertCountrySpecificCustomerResponse InsertCountrySpecificCustomer(InsertCountrySpecificCustomerRequest insertCustomerRequest)
{
	CountrySpecificCustomer newCustomer = BuildCountrySpecificCustomer(insertCustomerRequest.CountrySpecificCustomer);
	ThrowExceptionIfCustomerIsInvalid(newCustomer);
	try
	{
		_repository.Insert(newCustomer);
		UnitOfWork.Commit();
		return new InsertCountrySpecificCustomerResponse();
	}
	catch (Exception ex)
	{
		return new InsertCountrySpecificCustomerResponse() { Exception = ex };
	}
}

BuildCountrySpecificCustomer and ThrowExceptionIfCustomerIsInvalid look as follows:

private CountrySpecificCustomer BuildCountrySpecificCustomer(CountrySpecificCustomerViewModel viewModel)
{
	return new CountrySpecificCustomer(_countryFactory.CreateCountry(viewModel.CountryCode))
	{
		Age = viewModel.Age
		, Email = viewModel.Email
		, FirstName = viewModel.FirstName
		, NickName = viewModel.NickName
	};
}

private void ThrowExceptionIfCustomerIsInvalid(CountrySpecificCustomer newCustomer)
{
	IEnumerable<BusinessRule> brokenRules = newCustomer.GetBrokenRules();
	if (brokenRules.Count() > 0)
	{
		StringBuilder brokenRulesBuilder = new StringBuilder();
		brokenRulesBuilder.AppendLine("There were problems saving the LoadtestPortalCustomer object:");
		foreach (BusinessRule businessRule in brokenRules)
		{
			brokenRulesBuilder.AppendLine(businessRule.RuleDescription);
		}

		throw new Exception(brokenRulesBuilder.ToString());
	}
}

New elements in the Web layer

We’re now ready to construct our new Controller. Locate the Controllers folder in the WebService project of the solution. Add a new empty ApiController called CountrySpecificCustomersController. Add the following private field and constructor:

private readonly ICountrySpecificCustomerService _countrySpecificCustomerService;

public CountrySpecificCustomersController(ICountrySpecificCustomerService countrySpecificCustomerService)
{
	if (countrySpecificCustomerService == null) throw new ArgumentNullException("CountrySpecificCustomerService");
	_countrySpecificCustomerService = countrySpecificCustomerService;
}

We’ll only support the POST operation so that we can concentrate on validation. Add the following Post method to the controller:

public HttpResponseMessage Post(CountrySpecificCustomerViewModel viewModel)
{
	ServiceResponseBase response = _countrySpecificCustomerService.InsertCountrySpecificCustomer(new InsertCountrySpecificCustomerRequest() { CountrySpecificCustomer = viewModel });
	return Request.BuildResponse(response);
}

That’s it actually, we can now test the new parts using the simple Console tool we built in the last post of the DDD series. Start the DDD web service and take note of the localhost URL in the web browser. Insert a breakpoint within the Post method of the CountrySpecificCustomersController class so that you can go through the code step by step.

Open that little test application and add the following class to the main project:

public class CountrySpecificCustomerViewModel
{
	public string FirstName { get; set; }
	public int Age { get; set; }
	public string NickName { get; set; }
	public string Email { get; set; }
	public string CountryCode { get; set; }
}

Insert two methods that will build a valid and an invalid country specific customer:

private static CountrySpecificCustomerViewModel BuildFailingCustomer()
{
	return new CountrySpecificCustomerViewModel()
	{
		FirstName = "Elvis"
		, Age = 17
		, CountryCode = "SWE"
	};
}

private static CountrySpecificCustomerViewModel BuildPassingCustomer()
{
	return new CountrySpecificCustomerViewModel()
	{
		FirstName = "John"
		, Age = 19
		, CountryCode = "SWE"
	};
}

Recall that Swedish customers must be over 18, so the insertion of the first object should fail. Insert the following test method to Program.cs:

private static void TestCountrySpecificCustomerValidation()
{
	HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, _serviceUriTwo);
	requestMessage.Headers.ExpectContinue = false;
	CountrySpecificCustomerViewModel vm = BuildFailingCustomer();
	string jsonInputs = JsonConvert.SerializeObject(vm);
	requestMessage.Content = new StringContent(jsonInputs, Encoding.UTF8, "application/json");
	HttpClient httpClient = new HttpClient();
	httpClient.Timeout = new TimeSpan(0, 10, 0);
	Task<HttpResponseMessage> httpRequest = httpClient.SendAsync(requestMessage,
			HttpCompletionOption.ResponseContentRead, CancellationToken.None);
	HttpResponseMessage httpResponse = httpRequest.Result;
	HttpStatusCode statusCode = httpResponse.StatusCode;
	HttpContent responseContent = httpResponse.Content;
	if (responseContent != null)
	{
		Task<String> stringContentsTask = responseContent.ReadAsStringAsync();
		String stringContents = stringContentsTask.Result;
		Console.WriteLine("Response from service: " + stringContents);
	}
	Console.ReadKey();
}

…where _serviceUriTwo is the URL of the controller. It should be something like this:

private static Uri _serviceUriTwo = new Uri("http://localhost:9985/countryspecificcustomers");

So we’ll be testing the failing customer first. Insert a call to this test method from Main and press F5. If you entered the breakpoint mentioned above then the code execution should stop there. Step through the code and when it hits the validation part in the application service layer – the ThrowExceptionIfCustomerIsInvalid method – you should see a validation error: There were problems saving the LoadtestPortalCustomer object: Swedish customers must be at least 18.

Next replace the following…

CountrySpecificCustomerViewModel vm = BuildFailingCustomer();

…with…

CountrySpecificCustomerViewModel vm = BuildPassingCustomer();

…within the TestCountrySpecificCustomerValidation() method and run the test again. Validation should succeed without any problems.

Feel free to test the code with the other cases we set up in the original specifications by playing with the property values of the CountrySpecificCustomerViewModel object we send to the service.

That’s all folks. We’ll look at caching in the next extension of the DDD project.

View the list of posts on Architecture and Patterns here.

Extension to the DDD skeleton project: domain specific rules Part 1

Introduction

This post is a direct continuation of the series of posts on Domain Driven Design. Johannes asked in this post how to include rules in the domain that may vary from instance to instance. The idea is that the Validate() method may need to check different types of rules for a domain. I provided a simplified answer with code examples in my answer but I’d like to formalise the solution within the DDD skeleton project.

The scenario is the following:

  • We have an international e-commerce site where customers can order goods
  • The data required from a customer on the order form can vary depending on the country they are ordering from
  • We need to make sure that the country specific rules are enforced when a customer is created

There are potentially many countries the customers can order from. Let’s see some possible solutions that can come to one’s mind:

  • Extend the abstract Validate method in the EntityBase class so that it accepts some context parameter where we can send in some country identifier. The implemented method can check the context parameter and validate the Customer object in a series of if-else statements: if (country == “GER”) then. etc. That would result in a potentially very long if-else statement if we have a large number of countries on our commercial map. That is clearly not maintainable and does not properly reflect the importance of the rule. We would end up with a bloated and hard-to-test Customer class. Also, all other domain objects would have to implement the overloaded Validate method and send in some parameter that may not even be used. Therefore we can quickly rule out this option.
  • Make Customer abstract and create country specific concrete classes, such as GermanCustomer, FrenchCustomer etc. That would result in a very messy class structure and the importance of the country rule would still be hidden.
  • Continue with the current Customer class and let some external service do an extra validation on its behalf. One of the lessons we’ve learned from the DDD project is that each domain object should contain its own logic and should be able to validate itself. Domain logic should not be spread out in the solution, especially not in assemblies outside the domain

After dismissing the above proposals we come to the conclusion that we need a more object oriented solution and we need to elevate the country specific rule to an “objectified” form.

New components in the Domain layer

We’ll introduce a new domain: Country. This object won’t need an ID: we don’t need to differentiate between two Country objects with the same country code and country name. Therefore it will be a value object. Add the following class to the ValueObjects folder of the Domain layer:

public abstract class Country : ValueObjectBase
{
	public abstract string CountryCode { get; }
	public abstract string CountryName { get; }

	protected override void Validate()
	{
		if (string.IsNullOrEmpty(CountryCode)) AddBrokenRule(ValueObjectBusinessRule.CountryCodeRequired);
		if (string.IsNullOrEmpty(CountryName)) AddBrokenRule(ValueObjectBusinessRule.CountryNameRequired);
	}
}

The 2 new business rules in the ValueObjectBusinessRule container are as follows:

public static readonly BusinessRule CountryCodeRequired = new BusinessRule("Country must have a country code");
public static readonly BusinessRule CountryNameRequired = new BusinessRule("Country must have a name");

We won’t be adding new countries through some service call so the Validate method implementation is not strictly required. However it’s good to have the Validate method ready for the future.

Create 3 specific countries:

public class Germany : Country
{
	public override string CountryCode
	{
		get { return CountryCodes.Germany; }
	}

	public override string CountryName
	{
		get { return "Germany"; }
	}
}

public class Hungary : Country
{
	public override string CountryCode
	{
		get { return CountryCodes.Hungary; }
	}

	public override string CountryName
	{
		get { return "Hungary"; }
	}
}

public class Sweden : Country
{
	public override string CountryCode
	{
		get { return CountryCodes.Sweden; }
	}

        public override string CountryName
	{
		get { return "Sweden"; }
	}
}

The country codes are maintained in a separate container class:

public class CountryCodes
{
	public readonly static string Germany = "GER";
	public readonly static string Hungary = "HUN";
	public readonly static string Sweden = "SWE";
}

In reality the codes will probably be maintained and retrieved from a data store, but this quick solution will do for the time being.

We’ll let a factory return the specific country implementations:

public class CountryFactory
{
	private static IEnumerable<Country> AllCountries()
	{
		return new List<Country>() { new Hungary(), new Germany(), new Sweden() };
	}

	public static Country Create(string countryCode)
	{
		return (from c in AllCountries() where c.CountryCode.ToLower() == countryCode.ToLower() select c).FirstOrDefault();
	}
}

Let’s say we have the following country-related Customer rules:

  • All customers must have a first name
  • Swedish customers must be over 18
  • Hungarian customers must have a nickname
  • German customers must have an email address

The country specific rules will derive from the following base class:

public abstract class CountrySpecificCustomerRule
{
	public abstract Country Country { get; }
	public abstract List<BusinessRule> GetBrokenRules(CountrySpecificCustomer customer);
}

I’ve decided not to touch the Customer object that we created earlier in this series. We can have it for reference. Instead we have a new domain object: CountrySpecificCustomer. We’ll add that new class in a second. Before that let’s create the country specific implementations of the abstract rule:

public class GermanCustomerRule : CountrySpecificCustomerRule
{
	public override Country Country
	{
		get { return CountryFactory.Create(CountryCodes.Germany); }
	}

	public override List<BusinessRule> GetBrokenRules(CountrySpecificCustomer customer)
	{
		List<BusinessRule> brokenRules = new List<BusinessRule>();
		if (string.IsNullOrEmpty(customer.Email))
		{
			brokenRules.Add(new BusinessRule("German customers must have an email"));
		}
		return brokenRules;
	}
}

public class HungarianCustomerRule : CountrySpecificCustomerRule
{
	public override Country Country
	{
		get { return CountryFactory.Create(CountryCodes.Hungary); }
	}

	public override List<BusinessRule> GetBrokenRules(CountrySpecificCustomer customer)
	{
		List<BusinessRule> brokenRules = new List<BusinessRule>();
		if (string.IsNullOrEmpty(customer.NickName))
		{
			brokenRules.Add(new BusinessRule("Hungarian customers must have a nickname"));
		}
		return brokenRules;
	}
}

public class SwedishCustomerRule : CountrySpecificCustomerRule
{
	public override Country Country
	{
		get { return CountryFactory.Create(CountryCodes.Sweden); }
	}

	public override List<BusinessRule> GetBrokenRules(CountrySpecificCustomer customer)
	{
		List<BusinessRule> brokenRules = new List<BusinessRule>();
		if (customer.Age < 18)
		{
			brokenRules.Add(new BusinessRule("Swedish customers must be at least 18."));
		}
		return brokenRules;
	}
}

You’ll see that the implemented GetBrokenRules() methods reflect the country-specific requirements listed above.

The creation of the correct rule implementation will come from another factory:

public class CountrySpecificCustomerRuleFactory
{
	private static IEnumerable<CountrySpecificCustomerRule> GetAllCountryRules()
	{
		List<CountrySpecificCustomerRule> implementingRules = new List<CountrySpecificCustomerRule>()
		{
			new HungarianCustomerRule()
			, new SwedishCustomerRule()
			, new GermanCustomerRule()
		};
		return implementingRules;
	}

	public static CountrySpecificCustomerRule Create(Country country)
	{
		return (from c in GetAllCountryRules() where c.Country.CountryCode == country.CountryCode select c).FirstOrDefault();
	}
}

We’re now ready to insert the new domain:

public class CountrySpecificCustomer : EntityBase<int>, IAggregateRoot
{
	private Country _country;

	public CountrySpecificCustomer(Country country)
	{
		_country = country;
	}

	public string FirstName { get; set; }
	public int Age { get; set; }
	public string NickName { get; set; }
	public string Email { get; set; }

	protected override void Validate()
	{
		//overall rule
		if (string.IsNullOrEmpty(FirstName))
		{
			AddBrokenRule(new BusinessRule("All customers must have a first name"));
		}
		List<BusinessRule> brokenRules = new List<BusinessRule>();
		brokenRules.AddRange(CountrySpecificCustomerRuleFactory.Create(_country).GetBrokenRules(this));
		foreach (BusinessRule brokenRule in brokenRules)
		{
			AddBrokenRule(brokenRule);
		}
	}
}

We’ll also need an abstract repository:

public interface ICountrySpecificCustomerRepository : IRepository<CountrySpecificCustomer, int>
{
}

This completes the extension to the Domain layer.

New elements in the Repository.Memory layer

We’ll add a couple of stub implementations and objects related to the ICountrySpecificCustomerRepository interface. The goal is to demonstrate how the specific rules can be enforced across different CountrySpecificCustomer instances. We’ll not waste time around building a dummy repository around CountrySpecificCustomer like we did with the Customer object in the series. The implementations would be very similar anyway.

Enter the following empty database representation of the CountrySpecificCustomer object in the Database folder of the Repository layer:

public class DatabaseCountrySpecificCustomer
{
	//leave it empty
}

Enter the following stub implementation of the ICountrySpecificCustomerRepository interface:

public class CountrySpecificCustomerRepository : Repository<CountrySpecificCustomer, int, DatabaseCountrySpecificCustomer>
	, ICountrySpecificCustomerRepository
{
	public CountrySpecificCustomerRepository(IUnitOfWork unitOfWork, IObjectContextFactory objectContextFactory)
		: base(unitOfWork, objectContextFactory)
	{}

	public override CountrySpecificCustomer FindBy(int id)
	{
		return null;
	}

	public override DatabaseCountrySpecificCustomer ConvertToDatabaseType(CountrySpecificCustomer domainType)
	{
		return null;
	}

	public IEnumerable<CountrySpecificCustomer> FindAll()
	{
		return null;
	}
}

Again, we don’t care about the implementation of the Find methods. You can check the CustomerRepository for reference if you’d like to practice.

We’ll continue with the Service and Web layers and the tests in the next post.

View the list of posts on Architecture and Patterns here.

Design patterns and practices in .NET: the Service Locator anti-pattern

Introduction

The main responsibility of a Service Locator is to serve instances of services when consumers request them. The pattern is strongly linked to Dependency Injection and was introduced by Martin Fowler here.

The most common implementation of the pattern introduces a static factory. This factory can be configured with concrete services in the composition root of the application, such as global.asax, Main, etc., depending on the type of the application you’re developing. In other words the configuration happens before the first consumer can use it to extract a concrete service. Here you can think of a service as roughly equal to a dependency: the CustomerController has a dependency on ICustomerService. CustomerService has a dependency on ICustromerRepository etc. So when a concrete implementation of the abstraction is needed then the caller tries to grab it from the Service Locator.

A Service Locator is quite similar to Inversion-of-Control (IoC) containers at first. If you’re familiar with some IoCs such as StructureMap or CastleWindsor, then you’ll know that you can register your concrete types in the composition root. In StructureMap you can do this explicitly as follows:

x.For<ICustomerService>().Use<ConcreteCustomerService>();

The Service Locator configuration starts off in a similar manner. It’s essentially a dictionary of abstractions and their desired concrete types: ICustomerRepository – CustomerRepository; IProductService – ProductService. This is perfectly legitimate to do from the composition root. As we will see later consulting the service locator elsewhere in the application for concrete services is an anti-pattern.

Demo

We’ll simulate a dependency between the CustomerService and CustomerRepository classes where CustomerService requires a customer repository to consult the database for queries on the customer domain. Open Visual Studio and add the following standard generic implementation of a ServiceLocator:

public static class ServiceLocator
{
	private readonly static Dictionary<Type, object> _configuredServices = new Dictionary<Type, object>();

	public static T GetConfiguredService<T>()
	{
		return (T)ServiceLocator._configuredServices[typeof(T)];
	}

	public static void Register<T>(T service)
	{
		ServiceLocator._configuredServices[typeof(T)] = service;
	}
}

This is a very minimalistic implementation of the Service Locator. It’s void of exception handling, guard clauses, loading the dependency graph from an XML file but those features only add noise to the main discussion. The dependency map is stored in the private dictionary and the Register method is used, as you’ve probably guessed it, to register dependencies. It is analogous to the .For and .Use extension methods in the StructureMap example above. Let’s add the following interfaces and classes to see how the locator can be used:

public class Customer
{
}
public interface ICustomerService
{
	Customer GetCustomer(int id);
}
public interface ICustomerRepository
{
	Customer GetCustomerFromDatabase(int id);
}
public class CustomerRepository : ICustomerRepository
{
	public Customer GetCustomerFromDatabase(int id)
	{
		return new Customer();
	}
}
public class CustomerService : ICustomerService
{
	private ICustomerRepository _customerRepository;

	public CustomerService()
	{
		_customerRepository = ServiceLocator.GetConfiguredService<ICustomerRepository>();
	}

	public Customer GetCustomer(int id)
	{
		return _customerRepository.GetCustomerFromDatabase(id);
	}
}

You should be able to follow along this far. The CustomerService class resolves its own dependency using the ServiceLocator. You can configure the locator in Main as follows:

static void Main(string[] args)
{
	ServiceLocator.Register<ICustomerRepository>(new CustomerRepository());
	Customer c = new CustomerService().GetCustomer(54);
}

Main represents the composition root of a Console application so that’s where you can register the dependency graph. Step through the app with F11 and you’ll see that CustomerRepository is registered and retrieved as expected.

The CustomerService class can resolve its own dependency on ICustomerRepository, so what’s the problem? We can register our concrete implementations, retrieve the stored implementation where it’s needed, register Mock objects as concrete types in a Test Driven Design scenario, program against abstractions, write maintainable code, support late binding by changing the registration, so you’re a happy bunny, right? You shouldn’t be as the ServiceLocator class has a negative effect on the re-usability of the classes that consume it:

  • The ServiceLocator dependency will drag along if you try to re-use a class with a call to the locator
  • It is not obvious for external clients calling CustomerService() that Dependency Injection is used

The CustomerService will loosely depend on CustomerRepository through the ICustomerRepository interface. This is perfectly legitimate and valid. However, it will be tightly coupled to the ServiceLocator class. Here’s the dependency graph:

Dependency graph with service locator

If you want to distribute the CustomerService class then you’ll have to attach the ServiceLocator class to the package. It must come along even if the person that wants to use your class is not intending to use the ServiceLocator class in any way because they have their own Dependency Injection solution, such as StructureMap or CastleWindsor. Also, the consumer will need to set up ServiceLocator in the composition root otherwise they will get an exception. As the ServiceLocator may well reside in a different module, even that module must be redistributed for the CustomerService to be usable.

ProductService forces its users to follow the Dependency Injection strategy employed within it. There’s no room for other strategies unfortunately. Developers must simply accept the existence of the service locator. Also, there’s no way of telling that there’s a direct dependency just by looking at its signature which is what consumers will see first when creating a new CustomerService object. If the consumer doesn’t set up ServiceLocator appropriately then they will get an exception when using the CustomerService constructor. Depending on the exception handling strategy all they may get is a KeyNotFoundException. The consumer will then ask the questions: what key? Why is it not found? What are you talking about? WHY YOU NO WORK!!??? The consumer must know about the internals of the ConsumerService class which usually indicates a higher-than-desired level of coupling.

We can therefore rule out this patterns as it brings with it a fully redundant dependency which we can get rid of easily using constructor injection:

public CustomerService(ICustomerRepository customerRepository)
{
	_customerRepository = customerRepository;
}

There’s simply no advantage with this pattern that cannot be solved with an alternative solution such as constructor injection coupled with an IoC container. ProductService as it stands is not self-documenting. Its signature does not reveal anything about its dependency needs. Imagine that you download this API from NuGet and call CustomerService service = new CustomerService(). Your assumption would be that this is a fairly simple class that does not have any external dependencies which is not true as it turns out.

You can misuse IoC containers in the same way actually. It’s fine to use IoCs to resolve your dependencies “behind the scenes” but they – or at least some of them – allow the users to fetch concrete types from the container. In StructureMap you’d do it as follows:

StructureMap.ObjectFactory.Container.GetInstance<CustomerRepository>()

You should avoid using this type of dependency resolution for the same reasons why you wouldn’t use a ServiceLocator and its GetConfiguredService method.

Note that this pattern being an anti-pattern is a controversial topic. You can check out this post that offers another viewpoint and argues that Service Locator is indeed a proper design pattern.

View the list of posts on Architecture and Patterns here.

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: