Externalising dependencies with Dependency Injection in .NET part 8: symmetric cryptography

Introduction

In the previous post of this series we looked at how to hide the implementation of emailing operations. In this post we’ll look at abstracting away cryptography. Cryptography is often needed to communicate between two systems in a safe way by e.g. exchanging public keys first.

If you don’t know how to use cryptography in a .NET project check out the posts on this page.

The first couple of posts of this series went through the process of making hard dependencies to loosely coupled ones. I won’t go through that again – you can refer back to the previous parts of this series to get an idea. You’ll find a link below to view all posts of the series. Another post on the Single Responsibility Principle includes an example of breaking out different dependencies that you can look at.

We’ll extend the Infrastructure layer of our demo app we’ve been working on so far. So have it ready in Visual Studio and let’s get to it.

Cryptography in .NET

We discussed Cryptography in .NET on this blog before:

If you’re interested in the technical details then please consult those pages. I won’t go into cryptography in .NET but rather concentrate on the dependency injection side of it. We’ll abstract away all four of the above topics. As it’s a lot of code I’ve decided to break up the post into three parts:

  • This post: symmetric encryption
  • Next post: asymmetric encryption
  • Last post: hashing and digital signatures

Preparation

Add a new folder called Cryptography to the Infrastructure.Common library. We’ll follow the same methodology as in the case of emailing and communicate with proper objects as parameters and return types instead of writing a large amount of overloaded methods.

All return types will have 2 properties in common: Success and ExceptionMessage. A lot of things can go wrong in cryptography: wrong key size, unsupported block size, incomplete public/private key etc. The boolean property Success will indicate if the process was carried out successfully. ExceptionMessage will store the exception message in case Success is false. Insert the following abstract class to the Cryptography folder:

public abstract class ResponseBase
{
	public bool Success { get; set; }
	public string ExceptionMessage { get; set; }
}

Symmetric encryption

Symmetric algorithm in a nutshell means that both the message sender and receiver have access to the same cryptographic key for both encryption and decryption.

Insert a subfolder called Symmetric within the Cryptography folder.

I think any reasonable symmetric encryption implementation should be able to perform the following 3 operations:

  • Create a valid key of a given size in bits
  • Encrypt a text
  • Decrypt a cipher text

Add the following interface to the Symmetric folder to reflect these expectations:

public interface ISymmetricCryptographyService
{
	SymmetricKeyGenerationResult GenerateSymmetricKey(int bitSize);
	SymmetricEncryptionResult Encrypt(SymmetricEncryptionArguments arguments);
	CipherTextDecryptionResult Decrypt(SymmetricDecryptionArguments arguments);
}

SymmetricKeyGenerationResult is simple: it will contain the symmetric key and inherit from ResponseBase:

public class SymmetricKeyGenerationResult : ResponseBase
{
	public string SymmetricKey { get; set; }
}

SymmetricEncryptionResult will contain the encoded version of the plain text, called cipher text, and an initialisation vector (IV) for increased security. Note that IV is not always used but it’s highly recommended as it adds randomness to the resulting cipher text making brute force decryption harder. Insert the following class to the Symmetric folder:

public class SymmetricEncryptionResult : ResponseBase
{
	public string CipherText { get; set; }
	public string InitialisationVector { get; set; }		
}

There’s a number of arguments that will be necessary to both encryption and decryption such as the key size and the common key. Add the following abstract class to the subfolder:

public class CommonSymmetricCryptoArguments
{
	public int KeySize { get; set; }
	public int BlockSize { get; set; }
	public PaddingMode PaddingMode { get; set; }
	public CipherMode CipherMode { get; set; }
	public string SymmetricPublicKey { get; set; }
}

Both SymmetricEncryptionArguments and SymmetricDecryptionArguments will inherit from the above base class. Insert the following classes to the Asymmetric subfolder:

public class SymmetricEncryptionArguments : CommonSymmetricCryptoArguments
{
	public string PlainText { get; set; }		
}
public class SymmetricDecryptionArguments : CommonSymmetricCryptoArguments
{
	public string CipherTextBase64Encoded { get; set; }
	public string InitialisationVectorBase64Encoded { get; set; }
}

So we’ll send in the plain text to be encrypted in SymmetricEncryptionArguments along with all other common arguments in CommonSymmetricCryptoArguments. Decryption will need the cipher text, the IV and the common arguments in CommonSymmetricCryptoArguments.

The last missing piece is CipherTextDecryptionResult. This object will be re-used for the asymmetric encryption section and will only include one extra property, namely the decoded text. Therefore add it to the Cryptography and not the Symmetric folder:

public class CipherTextDecryptionResult : ResponseBase
{
	public string DecodedText { get; set; }
}

The code should compile at this stage so we can move on with the implementation of the ISymmetricCryptographyService interface.

The implementation: Rijndael

For the implementation we’ll take the widely used Rijndael managed implementation of symmetric encryption available in .NET. Add a new class called RijndaelManagedSymmetricEncryptionService to the Symmetric folder:

public class RijndaelManagedSymmetricEncryptionService : ISymmetricCryptographyService
{
	public SymmetricEncryptionResult Encrypt(SymmetricEncryptionArguments arguments)
	{			
		SymmetricEncryptionResult res = new SymmetricEncryptionResult();
		try
		{
			RijndaelManaged rijndael = CreateCipher(arguments);
			res.InitialisationVector = Convert.ToBase64String(rijndael.IV);
			ICryptoTransform cryptoTransform = rijndael.CreateEncryptor();
			byte[] plain = Encoding.UTF8.GetBytes(arguments.PlainText);
			byte[] cipherText = cryptoTransform.TransformFinalBlock(plain, 0, plain.Length);
			res.CipherText = Convert.ToBase64String(cipherText);				
			res.Success = true;
		}
		catch (Exception ex)
		{
			res.ExceptionMessage = ex.Message;
		}
		return res;
	}

	public CipherTextDecryptionResult Decrypt(SymmetricDecryptionArguments arguments)
	{
		CipherTextDecryptionResult res = new CipherTextDecryptionResult();
		try
		{
			RijndaelManaged cipher = CreateCipher(arguments);
			cipher.IV = Convert.FromBase64String(arguments.InitialisationVectorBase64Encoded);
			ICryptoTransform cryptTransform = cipher.CreateDecryptor();
			byte[] cipherTextBytes = Convert.FromBase64String(arguments.CipherTextBase64Encoded);
			byte[] plainText = cryptTransform.TransformFinalBlock(cipherTextBytes, 0, cipherTextBytes.Length);
			res.DecodedText = Encoding.UTF8.GetString(plainText);
			res.Success = true;
		}
		catch (Exception ex)
		{
			res.ExceptionMessage = ex.Message;
		}
		return res;
	}

	public SymmetricKeyGenerationResult GenerateSymmetricKey(int bitSize)
	{
		SymmetricKeyGenerationResult res = new SymmetricKeyGenerationResult();
		try
		{
			byte[] key = new byte[bitSize / 8];
			RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
			rng.GetBytes(key);
			res.SymmetricKey = BitConverter.ToString(key).Replace("-", string.Empty);
			res.Success = true;
		}
		catch (Exception ex)
		{
			res.ExceptionMessage = ex.Message;
		}
		return res;
	}

	private RijndaelManaged CreateCipher(CommonSymmetricCryptoArguments arguments)
	{
		RijndaelManaged cipher = new RijndaelManaged();
		cipher.KeySize = arguments.KeySize;
		cipher.BlockSize =  arguments.BlockSize;
		cipher.Padding = arguments.PaddingMode;
		cipher.Mode = arguments.CipherMode;
		byte[] key = HexToByteArray(arguments.SymmetricPublicKey);
		cipher.Key = key;
		return cipher;
	}

	private byte[] HexToByteArray(string hexString)
	{
		if (0 != (hexString.Length % 2))
		{
			throw new ApplicationException("Hex string must be multiple of 2 in length");
		}
		int byteCount = hexString.Length / 2;
		byte[] byteValues = new byte[byteCount];
		for (int i = 0; i < byteCount; i++)
		{
			byteValues[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
		}

		return byteValues;
	}		
}

This code should be quite straightforward – again, consult the posts on symmetric encryption if this is new to you.

The methods in the interface can be chained together in an example as follows:

private static void TestSymmetricEncryptionService()
{
	ISymmetricCryptographyService symmetricService = new RijndaelManagedSymmetricEncryptionService();
	SymmetricKeyGenerationResult validKey = symmetricService.GenerateSymmetricKey(128);
	if (validKey.Success)
	{
		Console.WriteLine("Key used for symmetric encryption: {0}", validKey.SymmetricKey);

		SymmetricEncryptionArguments encryptionArgs = new SymmetricEncryptionArguments()
		{
			BlockSize = 128
			,CipherMode = System.Security.Cryptography.CipherMode.CBC
			,KeySize = 256
			,PaddingMode = System.Security.Cryptography.PaddingMode.ISO10126
			,PlainText = "Text to be encoded"
			,SymmetricPublicKey = validKey.SymmetricKey
		};

		SymmetricEncryptionResult encryptionResult = symmetricService.Encrypt(encryptionArgs);

		if (encryptionResult.Success)
		{
			Console.WriteLine("Cipher text from encryption: {0}", encryptionResult.CipherText);
			Console.WriteLine("Initialisation vector from encryption: {0}", encryptionResult.InitialisationVector);
			SymmetricDecryptionArguments decryptionArgs = new SymmetricDecryptionArguments()
			{
				BlockSize = encryptionArgs.BlockSize
				,CipherMode = encryptionArgs.CipherMode
				,CipherTextBase64Encoded = encryptionResult.CipherText
				,InitialisationVectorBase64Encoded = encryptionResult.InitialisationVector
				,KeySize = encryptionArgs.KeySize
				,PaddingMode = encryptionArgs.PaddingMode
				,SymmetricPublicKey = validKey.SymmetricKey
			};
			CipherTextDecryptionResult decryptionResult = symmetricService.Decrypt(decryptionArgs);
			if (decryptionResult.Success)
			{
				Console.WriteLine("Decrypted text: {0}", decryptionResult.DecodedText);
			}
			else
			{
				Console.WriteLine("Decryption failure: {0}", decryptionResult.ExceptionMessage);
			}
		}
		else
		{
			Console.WriteLine("Encryption failure: {0}", encryptionResult.ExceptionMessage);
		}
	}
	else
	{
		Console.WriteLine("Symmetric key generation failure: {0}", validKey.ExceptionMessage);
	}
}

In short we generate a valid symmetric key of 128 bits, populate the common encryption arguments, provided a plain text, encrypt it and then decrypt the cipher text using the common arguments and the IV.

In the next post we’ll look at asymmetric encryption.

View the list of posts on Architecture and Patterns here.

Externalising dependencies with Dependency Injection in .NET part 7: emailing

Introduction

In the previous post of this series we looked at how to hide the implementation of file system operations. In this post we’ll look at abstracting away emailing. Emails are often sent out in professional applications to users in specific scenarios: a new user signs up, the user places an order, the order is dispatched etc.

If you don’t know who to send emails using .NET then check the out mini-series on this page.

The first couple of posts of this series went through the process of making hard dependencies to loosely coupled ones. I won’t go through that again – you can refer back to the previous parts of this series to get an idea. You’ll find a link below to view all posts of the series. Another post on the Single Responsibility Principle includes another example of breaking out an INotificationService that you can look at.

We’ll extend the Infrastructure layer of our demo app we’ve been working on so far. So have it ready in Visual Studio and let’s get to it.

The interface

As usual we’ll need an abstraction to hide the concrete emailing logic. Emailing has potentially a considerable amount of parameters: from, to, subject, body, attachments, HTML contents, embedded resources, SMTP server and possibly many more. So the interface method(s) should accommodate all these variables somehow. One approach is to create overloads of the same method, like…

void Send(string to, string from, string subject, string body, string smtpServer);
void Send(string to, string from, string subject, string body, string smtpServer, bool isHtml);
void Send(string to, string from, string subject, string body, string smtpServer, bool isHtml, List<string> attachments);
.
.
.

…and so on including all combinations, e.g. a method with and without “isHtml”. I think this is not an optimal and future-proof interface. It is probably better to give room to all those arguments in an object and use that object as the parameter to a single method in the interface.

Also, we need to read the response of the operation. Add a new folder call Email to the Infrastructure.Common library. Insert the following object into the folder:

public class EmailSendingResult
{
	public bool EmailSentSuccessfully { get; set; }
	public string EmailSendingFailureMessage { get; set; }
}

The parameters for sending the email will be contained by an object called EmailArguments:

public class EmailArguments
{
	private string _subject;
	private string _message;
	private string _to;
	private string _from;
	private string _smtpServer;
	private bool _html;
		
	public EmailArguments(string subject, string message, string to, string from, string smtpServer, bool html)
	{
		if (string.IsNullOrEmpty(subject))
			throw new ArgumentNullException("Email subject");
		if (string.IsNullOrEmpty(message))
			throw new ArgumentNullException("Email message");
		if (string.IsNullOrEmpty(to))
			throw new ArgumentNullException("Email recipient");
		if (string.IsNullOrEmpty(from))
			throw new ArgumentNullException("Email sender");
		if (string.IsNullOrEmpty(smtpServer))
			throw new ArgumentNullException("Smtp server");
		this._from = from;
		this._message = message;
		this._smtpServer = smtpServer;
		this._subject = subject;
		this._to = to;
		this._html = html;
	}

	public List EmbeddedResources { get; set; }

	public string To
	{
		get
		{
			return this._to;
		}
	}

	public string From
	{
		get
		{
			return this._from;
		}
	}

	public string Subject
	{
		get
		{
			return this._subject;
		}
	}

	public string SmtpServer
	{
		get
		{
			return this._smtpServer;
		}
	}

	public string Message
	{
		get
		{
			return this._message;
		}
	}

	public bool Html
	{
		get
		{
			return this._html;
		}
	}
}

…where EmbeddedEmailResource is a new object, we’ll show it in a second.

So 6 parameters are made compulsory: to, from, subject, smtpServer, message body and whether the message is HTML. We can probably make this list shorter by excluding the subject and isHtml parameters but it’s a good start.

Embedded email resources come in many different forms. Insert the following enum in the Email folder:

public enum EmbeddedEmailResourceType
{
	Jpg
	, Gif
	, Tiff
	, Html
	, Plain
	, RichText
	, Xml
	, OctetStream
	, Pdf
	, Rtf
	, Soap
	, Zip
}

Embedded resources will be represented by the EmbeddedEmailResource object:

public class EmbeddedEmailResource
{
	public EmbeddedEmailResource(Stream resourceStream, EmbeddedEmailResourceType resourceType
		, string embeddedResourceContentId)
	{
		if (resourceStream == null) throw new ArgumentNullException("Resource stream");
		if (String.IsNullOrEmpty(embeddedResourceContentId)) throw new ArgumentNullException("Resource content id");
		ResourceStream = resourceStream;
		ResourceType = resourceType;
		EmbeddedResourceContentId = embeddedResourceContentId;
	}

	public Stream ResourceStream { get; set; }
	public EmbeddedEmailResourceType ResourceType { get; set; }
	public string EmbeddedResourceContentId { get; set; }
}

If you’re familiar with how to add embedded resources to an email then you’ll know why we need a Stream and a content id.

The solution should compile at this stage.

We’re now ready for the great finale, i.e. the IEmailService interface:

public interface IEmailService
{
	EmailSendingResult SendEmail(EmailArguments emailArguments);
}

Both the return type and the single parameter are custom objects that can be extended without breaking the code for any existing callers. You can add new public getters and setters to EmailArguments instead of creating the 100th different version of SendEmail in the version with primitive parameters.

Implementation

We’ll of course use the default emailing techniques built into .NET to implement IEmailService. Add a new class called SystemNetEmailService to the Email folder:

public EmailSendingResult SendEmail(EmailArguments emailArguments)
{
	EmailSendingResult sendResult = new EmailSendingResult();
	sendResult.EmailSendingFailureMessage = string.Empty;
	try
	{
		MailMessage mailMessage = new MailMessage(emailArguments.From, emailArguments.To);
		mailMessage.Subject = emailArguments.Subject;
		mailMessage.Body = emailArguments.Message;
		mailMessage.IsBodyHtml = emailArguments.Html;
		SmtpClient client = new SmtpClient(emailArguments.SmtpServer);

		if (emailArguments.EmbeddedResources != null && emailArguments.EmbeddedResources.Count > 0)
		{
			AlternateView avHtml = AlternateView.CreateAlternateViewFromString(emailArguments.Message, Encoding.UTF8, MediaTypeNames.Text.Html);
			foreach (EmbeddedEmailResource resource in emailArguments.EmbeddedResources)
			{
				LinkedResource linkedResource = new LinkedResource(resource.ResourceStream, resource.ResourceType.ToSystemNetResourceType());
				linkedResource.ContentId = resource.EmbeddedResourceContentId;
				avHtml.LinkedResources.Add(linkedResource);
			}
			mailMessage.AlternateViews.Add(avHtml);
		}

		client.Send(mailMessage);
		sendResult.EmailSentSuccessfully = true;
	}
	catch (Exception ex)
	{
		sendResult.EmailSendingFailureMessage = ex.Message;
	}

	return sendResult;
}

The code won’t compile due to the extension method ToSystemNetResourceType(). The LinkedResource object cannot work with our EmbeddedEmailResourceType type directly. It needs a string instead like “text/plain” or “application/soap+xml”. Those values are in turn stored within the MediaTypeNames object.

Add the following static class to the Email folder:

public static class EmailExtensions
{
	public static string ToSystemNetResourceType(this EmbeddedEmailResourceType resourceTypeEnum)
	{
		string type = MediaTypeNames.Text.Plain;
		switch (resourceTypeEnum)
		{
			case EmbeddedEmailResourceType.Gif:
				type = MediaTypeNames.Image.Gif;
				break;
			case EmbeddedEmailResourceType.Jpg:
				type = MediaTypeNames.Image.Jpeg;
				break;
			case EmbeddedEmailResourceType.Html:
				type = MediaTypeNames.Text.Html;
				break;
			case EmbeddedEmailResourceType.OctetStream:
				type = MediaTypeNames.Application.Octet;
				break;
			case EmbeddedEmailResourceType.Pdf:
				type = MediaTypeNames.Application.Pdf;
				break;
			case EmbeddedEmailResourceType.Plain:
				type = MediaTypeNames.Text.Plain;
				break;
			case EmbeddedEmailResourceType.RichText:
				type = MediaTypeNames.Text.RichText;
				break;
			case EmbeddedEmailResourceType.Rtf:
				type = MediaTypeNames.Application.Rtf;
				break;
			case EmbeddedEmailResourceType.Soap:
				type = MediaTypeNames.Application.Soap;
				break;
			case EmbeddedEmailResourceType.Tiff:
				type = MediaTypeNames.Image.Tiff;
				break;
			case EmbeddedEmailResourceType.Xml:
				type = MediaTypeNames.Text.Xml;
				break;
			case EmbeddedEmailResourceType.Zip:
				type = MediaTypeNames.Application.Zip;
				break;
		}

		return type;
	}
}

This is a simple converter extension to transform our custom enumeration to media type strings.

There you are, this is a good starting point to cover the email purposes in your project.

In the next part of this series we’ll look at hiding the cryptography logic or our application.

View the list of posts on Architecture and Patterns here.

Externalising dependencies with Dependency Injection in .NET part 6: file system

Introduction

In the previous post we looked at logging with log4net and saw how easy it was to switch from one logging strategy to another. By now you probably understand why it can be advantageous to remove hard dependencies from your classes: flexibility, testability, SOLID and more.

The steps to factor out your hard dependencies to abstractions usually involve the following steps:

  • Identify the hard dependencies: can the class be tested in isolation? Does the test result depend on an external object such as a web service? Can the implementation of the dependency change?
  • Identify the tasks any reasonable implementation of the dependency should be able to perform: what should a caching system do? What should any decent logging framework be able to do?
  • Build an abstraction – usually an interface – to represent those expected functions: this is so that the interface becomes as future-proof as possible. As noted before this is easier said than done as you don’t know in advance what a future implementation might need. You might need to revisit your interface and add an extra method or an extra parameter. This can be alleviated if you work with objects as parameters to the interface functions, e.g. LoggingArguments, CachingArguments – you’ll see what I mean in the next post where we’ll take up emailing
  • Inject the abstraction into the class that depends on it through one of the Dependency Injection patterns where constructor injection should be your default choice if you’re uncertain
  • The calling class will then inject a concrete implementation for the interface – alternatively you can use of the Inversion-of-control tools, like StructureMap

In this and the remaining posts of this series we won’t be dealing with the Console app in the demo anymore. The purpose of the console app was to show the goal of abstractions and dependency injection through examples. We’ve seen enough of that so we can instead concentrate on building the infrastructure layer. So open the demo solution in VS let’s add file system operations to Infrastructure.Common.

File system

.NET has an excellent built-in library for anything you’d like to do with files and directories. In the previous post on log4net we saw an example of checking if a file exists like this:

FileInfo log4netSettingsFileInfo = new FileInfo(_contextService.GetContextualFullFilePath(_log4netConfigFileName));
if (!log4netSettingsFileInfo.Exists)
{
	throw new ApplicationException(string.Concat("Log4net settings file ", _log4netConfigFileName, " not found."));
}

You can have File.WriteAllText, File.ReadAllBytes, File.Copy etc. directly in your code and you may not think that it’s a real dependency. It’s admittedly very unlikely that you don’t want to use the built-in features of .NET for file system operations and instead take some other library. So the argument of “flexibility” might not play a big role here.

However, unit testing with TDD shows that you shouldn’t make the outcome of your test depend on external elements, such as the existence of a file if the method being tested wants in fact to perform some operation on a physical file. Instead, you should be able to declare the outcome of those operations through TDD tools such as Moq which is discussed in the TDD series referred to in the previous sentence. If you see that you must create a specific file before a test is run and delete it afterwards then it’s a brittle unit test. Most real-life business applications are auto-tested by test runners in continuous integration (CI) systems such as TeamCity or Jenkins. In that case you’ll need to create the same file on the CI server(s) as well so that the unit test passes.

Therefore it still makes sense to factor out the file related stuff from your consuming classes.

The abstraction

File system operations have many facets: reading, writing, updating, deleting, copying, creating files and much more. Therefore a single file system interface is going to be relatively large. Alternatively you can break out the functions to separate interfaces such as IFileReaderService, IFileWriterService, IFileInformationService etc. You can also have a separate interface for directory-specific operations such as creating a new folder or reading the drive name.

Here we’ll start with out easy. Add a new folder called FileOperations to the Infrastructure.Common C# library. Insert an interface called IFileService:

public interface IFileService
{		
	bool FileExists(string fileFullPath);		
	long LastModifiedDateUnix(string fileFullPath);		
	string RetrieveContentsAsBase64String(string fileFullPath);		
	byte[] ReadContentsOfFile(string fileFullPath);		
	string GetFileName(string fullFilePath);		
	bool SaveFileContents(string fileFullPath, byte[] contents);		
	bool SaveFileContents(string fileFullPath, string base64Contents);			
	string GetFileExtension(string fileName);		
	bool DeleteFile(string fileFullPath);
}

That should be enough for starters.

The implementation

We’ll of course use the standard capabilities in .NET to implement the file operations. Add a new class called DefaultFileService to the FileOperations folder:

public class DefaultFileService : IFileService
{
	public bool FileExists(string fileFullPath)
	{
		FileInfo fileInfo = new FileInfo(fileFullPath);
		return fileInfo.Exists;
	}

	public long LastModifiedDateUnix(string fileFullPath)
	{
		FileInfo fileInfo = new FileInfo(fileFullPath);
		if (fileInfo.Exists)
		{
			DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0);
			TimeSpan timeSpan = fileInfo.LastWriteTimeUtc - epoch;
			return Convert.ToInt64(timeSpan.TotalMilliseconds);
		}

		return -1;
	}

	public string RetrieveContentsAsBase64String(string fileFullPath)
	{
		byte[] contents = ReadContentsOfFile(fileFullPath);
		if (contents != null)
		{
			return Convert.ToBase64String(contents);
		}
		return string.Empty;
	}

	public byte[] ReadContentsOfFile(string fileFullPath)
	{
		FileInfo fi = new FileInfo(fileFullPath);
		if (fi.Exists)
		{
			return File.ReadAllBytes(fileFullPath);
		}

		return null;
	}

	public string GetFileName(string fullFilePath)
	{
		FileInfo fi = new FileInfo(fullFilePath);
		return fi.Name;
	}

	public bool SaveFileContents(string fileFullPath, byte[] contents)
	{
		try
		{
			File.WriteAllBytes(fileFullPath, contents);
			return true;
		}
		catch
		{
			return false;
		}
	}

	public bool SaveFileContents(string fileFullPath, string base64Contents)
	{
		return SaveFileContents(fileFullPath, Convert.FromBase64String(base64Contents));
	}

	public string GetFileExtension(string fileName)
	{
		FileInfo fi = new FileInfo(fileName);
		return fi.Extension;
	}

	public bool DeleteFile(string fileFullPath)
	{
		FileInfo fi = new FileInfo(fileFullPath);
		if (fi.Exists)
		{
			File.Delete(fileFullPath);
		}

		return true;
	}
}

There you have it. Feel free to break out the file system functions to separate interfaces as suggested above.

The next post in this series will take up emailing.

View the list of posts on Architecture and Patterns here.

4 design patterns to learn with C# .NET

Here come 4 well-known design patterns that I think most developers will benefit from, even those that are by nature anti-designpattern. Note that the list is biased and only shows the ones that I personally use the most often in my work.

If you don’t find the solution to your design problem here then check out the full list of patterns discussed on this blog here.

  • Adapter: this pattern helps you hide the functionality of a class which is not under your control behind an abstraction
  • Strategy: this pattern will help you with cleaning up anti-SOLID code where you check for certain properties, especially the type of an object to tweak your code. You will end up with proper objects instead of brittle switch or if-else statements
  • Decorator: if you’d like to extend the functionality of a class without changing its implementation then this pattern is something to consider. You can build compound objects by nesting decorators where the individual elements are still standalone classes.
  • Factory: this pattern will help you build objects using parameters whose values are not known beforehand. E.g. if you don’t which concrete type of an abstract class to return then hide that build functionality behind an abstract factory

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.

Elliot Balynn's Blog

A directory of wonderful thoughts

HarsH ReaLiTy

A Good Blog is Hard to Find

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: