Pages

Monday 7 May 2012

Interception and ServiceLocator in Unity

This time I would like to familiarize you with two interesting concepts of Unity (IoC Container) which you can find very useful.

Interceptors allow programmers to run some functionality before or after a selected piece of code. This approach is called Aspect-Oriented Programming (AOP) and its main goal is to increase modularity through separation of cross-cutting concerns e.g. logging messages before and after a code execution. The following example shows how easy you can apply logging in a method using a [MethodHandler()] attribute. 

ServiceLocator is an excellent concept of the Unity but I do not like the fact that it can be easily abused and overdosed. An example below shows two different approaches for creating an instance of a Logger class.  First one is using constructor injection and the second one is using ServiceLocator (have a look at the constructors). The only one case scenario when ServiceLocator seems to be very useful is a situation when we have a class created outside of the Unity and this class needs access to the other types registered in a container. An example below shows how to make ServiceLocator aware of the Unity.

   1:          class Program
   2:          {
   3:              static void Main(string[] args)
   4:              {
   5:                  IUnityContainer unity = new UnityContainer();
   6:                  UnityServiceLocator locator = new UnityServiceLocator(unity);
   7:                  ServiceLocator.SetLocatorProvider(() => locator);
   8:   
   9:                  unity.AddNewExtension<Interception>();
  10:                  unity.RegisterType<ILogger, Logger>();
  11:                  unity.RegisterType<ITest, Test>().Configure<Interception>().SetDefaultInterceptorFor<ITest>(new InterfaceInterceptor());
  12:   
  13:                  unity.Resolve<ITest>().Execute();
  14:                  Console.ReadKey();
  15:              }
  16:          }
  17:   
  18:          public class Test : ITest
  19:          {
  20:              public void Execute()
  21:              {
  22:                  Console.WriteLine("Execute Method Body");
  23:              }
  24:          }
  25:   
  26:          public interface ITest
  27:          {
  28:              [MethodHandler()]
  29:              void Execute();
  30:          }
  31:   
  32:          public class CallHandler : ICallHandler
  33:          {
  34:              private IUnityContainer _container;
  35:              private ILogger _logger;
  36:   
  37:              public CallHandler(IUnityContainer container, ILogger logger)
  38:              {
  39:                  _logger = logger;
  40:              }
  41:   
  42:              public CallHandler()
  43:              {
  44:                  _logger = ServiceLocator.Current.GetInstance<ILogger>();
  45:              }
  46:   
  47:              public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
  48:              {
  49:                  _logger.LogPreMessage(input.MethodBase.Name);
  50:                  IMethodReturn methodReturn = getNext()(input, getNext);
  51:                  _logger.LogPostMessage(input.MethodBase.Name);
  52:                  return methodReturn;
  53:              }
  54:   
  55:              public int Order
  56:              {
  57:                  get;
  58:                  set;
  59:              }
  60:          }
  61:   
  62:          public class MethodHandlerAttribute : HandlerAttribute
  63:          {
  64:              public MethodHandlerAttribute()
  65:              {
  66:              }
  67:   
  68:              public override ICallHandler CreateHandler(IUnityContainer container)
  69:              {
  70:                  return new CallHandler(container);
  71:              }
  72:          }
  73:   
  74:          interface ILogger
  75:          {
  76:              void LogPreMessage(string msg);
  77:              void LogPostMessage(string msg);
  78:          }
  79:   
  80:          class Logger : ILogger
  81:          {
  82:              public void LogPreMessage(string msg)
  83:              {
  84:                  Console.WriteLine("Pre -> " + msg);
  85:              }
  86:   
  87:              public void LogPostMessage(string msg)
  88:              {
  89:                  Console.WriteLine("Post -> " + msg);
  90:              }
  91:          }
  92:      }

Useful links: