Interception using Dependency Injection Container (Unity) to achieve separation of concerns

It is quite important to follow some kind of design guidelines to achieve extensible software. There are many articles on the internet describing the benefits of modular design in any level (enterprise, mid-sized, small) of applications.

Using separation of concerns makes our life easier when it comes to refactoring one of the elements or even replacing it with something more functional. Each element of your application focuses on just one task and completes it without worrying about other layers like exception handling, logging or displaying results. To achieve the concept of modularity, it’s important to decouple modules when building the application. In developers language, we say that our architecture is either tightly or loosely coupled. Where the latter is in most cases the best approach, there are many developers out there still not adhering to this design pattern. As a result, produced code is hard to maintain, test and extend.

Dependency Injection

One commonly used design pattern to achieve loose coupling is dependency injection (DI). Simply stated, high level objects should not be responsible for resolving their dependencies by requesting object instances of the types that they need. The control of the instance creation should be handed over to another object. We call it Inversion of Control and that’s what DI containers are designed for. Containers take the responsibility of object instance management away from the high level object, decoupling it from the entire application.

Dependency Injection is not programming language specific. Ideology of loose coupling is used in any object oriented programming languages when creating flexible applications. In this post I’ll be focusing just on .NET C# and Microsoft’s Unity container, but other languages are successfully using their own containers to achieve the same goal. For example, Java has it’s Spring framework, Google Guice or PICO, and in Javascript there is wire.js. On the other hand, in the really popular, dynamic language Ruby, – I have not heard about any DI container available.

In my quick example on how to use a DI Container Interception (Unity in this example) to separate business logic from viewing the result, I’ll use the simplest Calculator application. I need to prepare the code before I can move to Interception.

First of all, I will need a contract that will define our module and its methods. ICalculator interface delivers four methods:

public interface ICalculator { 
  int Add(int number1, int number2); 
  int Subtract(int number1, int number2); 
  int Multiply(int number1, int number2); 
  int Divide(int number1, int number2); 
}

Performing four operations in a sequence will work as my business logic. Now, let’s code the actual implementation of above interface.

public class Calculator : ICalculator { 
  public int Add(int number1, int number2) { 
    return number1 + number2; 
  } 
  public int Subtract(int number1, int number2) { 
    return number1-number2; 
  } 
  public int Multiply(int number1, int number2) { 
    return number1*number2; 
  } 
  public int Divide(int number1, int number2) { 
    return number1/number2; 
  } 
}

My calculator is indeed performing these simple operations. For now I don’t care about anything else but adding, subtracting, multiplying or dividing two numbers.

At this point we have a contract interface defining our business logic and implementation of the interface – executing 4 tasks and producing (note: not viewing) result of four calculations. Let’s focus on putting these two together in a Console Application.

public class Program { 
  private static void Main(string[] args) { 
    ICalculator calculator = new Calculator(); 
    calculator.Add(5, 5); 
    calculator.Subtract(6, 5); 
    calculator.Multiply(5, 5); 
    calculator.Divide(10, 5); 
    Console.ReadLine(); 
  } 
} 

As a result, I get a simple application which does some calculations. It is a bit weird that I can’t actually see the results of four methods, but this is not relevant now. I have my business logic – one task that the Calculator is performing, not worrying about anything else. One of the issues I have here is the dependency on the concrete type of Calculator() class, something that I want to avoid, using Dependency Injection. Using DI container, I will be able to declare a concrete type for an interface outside of my application, hence removing the dependency.

To remove the dependency from Program, I need to provide a mapping so the container knows what type to use for an interface.

IUnityContainer container = new UnityContainer(); 
container.RegisterType();

These two lines of code have created a type mapping for my container. Now, to follow the idea of separation of concerns, I will treat mapping as configuration, so I need to move it outside of the main program body and let it be called once, when the program starts. I created a Bootstrap class to initiate the container and provide mappings used in the application lifetime.

public static class UnityBootstrap {
  public static void Bootstrap(IUnityContainer container) {
    container.RegisterType();
  }
}

Now I just need to call Bootstrap method to register mapping of ICalculator interface to a new instance of Calculator class in my program using containers Resolve method.

IUnityContainer container = new UnityContainer(); 
UnityBootstrap.Bootstrap(container); 
var calculator = container.Resolve();

At this stage, I have a program that executes business logic without any concrete class dependencies. It will serve as a base for presenting Interception and provide result viewer module. My program is responsible just for a single task now, so we will add another module (Interceptor) to decorate my Calculator methods with results display (in this case Console). I have an ICalculator interface, so I will use the Interface interception method provided by Unity. Unity creates a proxy object in the background and enables the interception of Interface methods.

First, I will code the DisplayInterceptor class – it will be responsible for gathering information about executed interface methods with name, parameters and the result of calculation. Next it will send this information to the Console, providing the missing result display functionality.

class DisplayInterceptor : IInterceptionBehavior { 
  public IEnumerable GetRequiredInterfaces() { 
    return Type.EmptyTypes; 
  } 
  public IMethodReturn Invoke( IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext ) { 
    IMethodReturn result = getNext()(input, getNext); 
    Console.WriteLine("{0} {1} and {2} result {3}", input.MethodBase.Name, input.Arguments["number1"], input.Arguments["number2"], result.ReturnValue); 
    return result; 
  }
  public bool WillExecute { 
    get { 
      return true; 
    } 
  }
}

Implementing the IInterceptionBehavior interface results in three elements in my new class. The GetRequiredInterfaces() will return Type.EmptyTypes value, simply because I don’t have any other interface dependencies for display purposes, other than ICalculator interface, which will have my interceptor attached in the configuration. The WillExecute getter indicates if the interceptor will actually run against my type. For now I’ll just return true, so it always runs when any method of the instance of my type is called. All I need to implement my viewer functionality will be contained in Invoke method. It has two parameters.

– Input object contains all the information about the method currently being invoked in my interface with the name, parameters etc. and getNext is a delegate which I can call to move to the next method in the behavior execution chain (in my case, to get result of Add, Subtract, Multiply or Divide methods). To display my operation result I will use Console.WriteLine method and structured string value consisting of method parameters, method name and returned value.

Console.WriteLine("{0} {1} and {2} result {3}", input.MethodBase.Name input.Arguments["number1"], input.Arguments["number2"], result.ReturnValue);

The usage is rather simple and self explanatory. Now when I have an interceptor definition, I need to add it to my UnityBootstrap configuration:

public static class UnityBootstrap { 
  public static void Bootstrap(IUnityContainer container) {
    container.AddNewExtension(); 
    container.RegisterType( new Interceptor(), new InterceptionBehavior()); 
  } 
}

First I tell Unity that I’m intending to use Interception extension container.AddNewExtension(); then I register interceptor with my type mapping, creating a new instance of InterceptionBehavior class.

Now the full code of the program looks like this:

private static void Main(string[] args) { 
  IUnityContainer container = new UnityContainer(); 
  UnityBootstrap.Bootstrap(container); 
  var calculator = container.Resolve(); 
  calculator.Add(5, 5); 
  calculator.Subtract(6, 5); 
  calculator.Multiply(5, 5); 
  calculator.Divide(10, 5); 
  Console.ReadLine(); 
}

After executing the application, instead of seeing a blank console window, I get following result:

Add 5 and 5 result 10 Subtract 6 and 5 result 1 Multiply 5 and 5 result 2 Divide 10 and 5 result 2

Conclusion

In this very simple example I have demonstrated how to plug in additional functionality into already built applications. I have separated the business logic and decorated it with a result display module, without amending my calculator code. It’s a very basic use of interception, so that you can see it in action. In a real life example, you can use this method to inject Logging or Exception handling without bloating your business logic code with unnecessary responsibilities. In this post I have achieved separation of concerns as expected. If you have any comments, feel free to leave them here.

Most Read

1 Team health & the retro
2 How to fold QA into every sprint
3 Cooking with the right ingredients - what's your "Definition of Ready"?
4 Android build optimization
5 Why CSS Grid will drive the web forward

Working with startups from concept to launch

We understand that creating a product is a challenging and risky endeavor and believe that having a partner with experience and know-how is a critical first step.

Learn More

The Startup Journey

From idea to launch we guide you through the startup experience

Learn More