First steps with Unity: DI / IoC & AOP

    Introduction


    If you have ever heard such words as IoC, DI, AoP, but do not have a clear understanding of these terms, I hope this article will help you to break into them using the Microsoft Unity container as an example.

    So, let's start the theory:

    Inversion of Control (IoC) and Dependency Injection (DI)


    For the definition of IoC, refer to Wikipedia :

    Handling Control * (Inversion of Control, IoC) - an important principle of object-oriented programming, which is used to reduce coupling in computer programs.

    IoC is also known as the Dependency Injection Principle. Dependency Injection is used in almost all frameworks. It is used by programmers using object-oriented programming languages ​​such as Smalltalk, C ++, Java, or the .NET platform languages.


    * I immediately wanted to make a reservation that I prefer not to use a Russian-language translation for IoC, but still if they force me to do this, I will use it as a “control inversion”

    For the definition of DI, we also turn to Wikipedia :

    Dependency Injection (Eng. Dependency injection) is the process of external dependence and software component is a specific form of "control treatment (Eng. Inversion of control)», where the change in the order of connection is by obtaining the necessary dependencies.


    A classic example for determining how tightly your application objects are linked to each other is an attempt to copy a class from your subject area into a new application and try to run it, if that does not work, then copy the related classes. Usually, as a result of these manipulations, your old application is almost completely copied to the new one.

    To solve the problems of dependencies of one object from another, it is usually the object that has the dependency that is responsible for creating / obtaining the object it needs (I would like to draw your attention to such templates as Factory, Registry, by the way ).

    There are a lot of examples of implementations with the pseudo-code IoC and DI; in this regard, I don’t really want the article to grow because of them, but I can hardly provide you with a better understanding than in practical use.

    I think it will be useful to list .NET DI / IoC containers here :



    Aspect-oriented programming (AoP)



    I admit, I am a meticulous Wikipedia fan :

    Aspect-oriented programming (AOP) is a programming paradigm based on the idea of ​​dividing functionality, especially end-to-end functionality, to improve the breakdown of a program into modules.


    I would like to add that Aspect-Oriented Programming (AOP) is also designed to come to the aid of OOP in order to reduce the amount of code written in applications.

    Most often, the use of AOP is reduced to the implementation of everyday routine tasks, such as logging, caching, validation, as well as access control. One can object and say that this problem can be solved by enveloping your business objects with the Decorator template ( Russian ), but the fact is that this necessitates changing the consumer code, and AOP allows you to do this easily and naturally.

    Famous frameworks:



    About Microsoft Enterprise Library


    As you know, in October 2008 Microsoft updated the Enterprise Library version to 4.1 , respectively, one of its Unity Application Block components to version 1.2 . Microsoft Enterprise Library is being developed by the patterns & practices group . Microsoft Enterprise Library is a set of functional blocks designed to help developers complete common routine tasks. Function blocks are a kind of manual, the source code provided as part of them can be used "as is", extended or modified by developers in accordance with their needs. Microsoft Enterprise Library consists of the following blocks:

    • Caching Application Block . Developers can use this block to implement caching in their applications. It also supports plug-in cache providers.
    • Cryptography Application Block . Developers can use this block to implement hashing and symmetric encryption in applications.
    • Data Access Application Block . Developers can use this block to implement standard database actions in their applications.
    • Exception Handling Application Block . Developers and rule editors can use this block to implement a consistent strategy for handling exceptions that occur on all architectural layers of enterprise applications.
    • Logging Application Block . Developers can use this block to implement standard logging functions.
    • Policy Injection Application Block . Developers can use this block to implement interception policies in order to saturate the application with capabilities such as logging, caching, exception handling, and application-wide validation.
    • Security Application Block . Developers can use this block to implement the authorization mechanism and application security.
    • Unity Application Block . Developers can use this block as a lightweight, extensible dependency injection container with support for injecting dependencies into the constructor, property and method calls, in the same way as implementing interception through extensions.
    • Validation Application Block . Developers can use this block to implement validation rules for business objects used in the application.


    About Unity Application Block



    A lightweight, extensible dependency injection container with support for injecting dependencies into the constructor, property and method calls, in the same way as the implementation of interception through extensions. You can use it together with the Enterprise Library (EntLib) to generate objects, both your own and the Enterprise Library. However, the Unity Application Block differs from the rest of the EntLib function blocks in several key ways:

    • You can use the Unity Application Block as a standalone dependency injection mechanism without having to have EntLib installed.
    • Unity Application Block can be configured both using specialized configuration files, and in run-time mode using your code.
    • The Unity Application Block is independent of the EntLib core, just like the EntLib configuration system. It contains its own configuration engine, although you can use the EntLib configuration mechanism if you wish.


    The long-awaited In Action



    Requirements



    For the example below to work, we need:

    1. Installed .NET Framework 3.5 SP1
    2. Your favorite IDE (Notepad .. Visual Studio 2008 SP1 )
    3. Installed by Unity
    4. 15-20 minutes of time and a little interest


    Process



    To get started, create a ConsoleApplication called UnityInAction1.

    Next, add links to the following assemblies:

    • Microsoft.Pratices.ObjectBulder2
    • Microsoft.Pratices.Unity
    • Microsoft.Pratices.Unity.Interception.


    Let's create the ILogger interface in our application:

    1. namespace UnityInAction1
    2. {
    3.     interface ILogger
    4.     {
    5.         void Write(string msg);
    6.     }
    7. }

    * This source code was highlighted with Source Code Highlighter.


    Next, we implement it in the Logger class:

    1. using System;
    2.  
    3. namespace UnityInAction1
    4. {
    5.     class Logger : ILogger
    6.     {
    7.         #region ILogger Members
    8.  
    9.         public void Write(string msg)
    10.         {
    11.             Console.WriteLine();
    12.             Console.WriteLine("*** In logger ***");
    13.             Console.WriteLine(String.Format("message {0}", msg));
    14.         }
    15.  
    16.         #endregion
    17.     }
    18. }

    * This source code was highlighted with Source Code Highlighter.


    This would be our regular application:

    1. using System;
    2.  
    3. namespace UnityInAction1
    4. {
    5.     class Program
    6.     {
    7.         static void Main(string[] args)
    8.         {
    9.             ILogger logger = new Logger();
    10.             logger.Write("Моё сообщение");
    11.             Console.ReadKey();
    12.         }
    13.     }
    14. }

    * This source code was highlighted with Source Code Highlighter.


    However, from the point of view of the IoC / DI approach, this does not quite suit us, in connection with this we want to place our Logger in a container (for example, in order to replace [and it will be necessary to replace only at the container configuration location, and not over the entire coverage code, as it usually happens] it is a stub when testing):

    1. using System;
    2. using Microsoft.Practices.Unity;
    3.  
    4. namespace UnityInAction1
    5. {
    6.     class Program
    7.     {
    8.         static void Main(string[] args)
    9.         {
    10.             IUnityContainer container = new UnityContainer();
    11.             container.RegisterType(new ContainerControlledLifetimeManager());
    12.  
    13.             var logger = container.Resolve();
    14.             logger.Write("Моё сообщение");
    15.             Console.ReadKey();
    16.         }
    17.     }
    18. }

    * This source code was highlighted with Source Code Highlighter.


    Well, I think this example is enough to start.

    Now we add the requirement of measuring the execution time of the ILogger.Write () method for all implementations of this interface, it is clear that with the help of OOP, the implementation of this condition becomes more difficult, therefore we look at this example from the point of view of AOP. First, let's redefine the ILogger description a bit by introducing a new .NET attribute :

    1. namespace UnityInAction1
    2. {
    3.     interface ILogger
    4.     {
    5.         [Stopwatch]
    6.         void Write(string msg);
    7.     }
    8. }

    * This source code was highlighted with Source Code Highlighter.


    Stopwatch attribute description:

    1. using System;
    2. using Microsoft.Practices.Unity.InterceptionExtension;
    3.  
    4. namespace UnityInAction1
    5. {
    6.     class Stopwatch : HandlerAttribute
    7.     {
    8.         public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)
    9.         {
    10.             return new StopwatchCallHandler();
    11.         }
    12.     }
    13.    
    14.     public class StopwatchCallHandler : ICallHandler
    15.     {
    16.         public int Order {get; set;}
    17.  
    18.         public StopwatchCallHandler() : this(0) {}
    19.  
    20.         public StopwatchCallHandler(int order)
    21.         {
    22.             Order = order;
    23.         }
    24.  
    25.         #region ICallHandler Members
    26.  
    27.         public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    28.         {
    29.             System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    30.             sw.Start();
    31.  
    32.             var result = getNext().Invoke(input, getNext);
    33.  
    34.             sw.Stop();
    35.  
    36.             Console.WriteLine();
    37.             Console.WriteLine(String.Format("Прошло времени {0} мс", sw.ElapsedMilliseconds));
    38.  
    39.             return result;
    40.         }
    41.  
    42.         #endregion
    43.     }
    44. }

    * This source code was highlighted with Source Code Highlighter.


    Well, add an extension for our container:

    1. using System;
    2. using Microsoft.Practices.Unity;
    3. using Microsoft.Practices.Unity.InterceptionExtension;
    4.  
    5. namespace UnityInAction1
    6. {
    7.     class Program
    8.     {
    9.         static void Main(string[] args)
    10.         {
    11.             IUnityContainer container = new UnityContainer();
    12.             container.RegisterType(new ContainerControlledLifetimeManager());
    13.             container.AddNewExtension();
    14.             container.Configure()
    15.                 .SetInterceptorFor(new TransparentProxyInterceptor());
    16.            
    17.             var logger = container.Resolve();
    18.             logger.Write("Моё сообщение");
    19.             Console.ReadKey();
    20.         }
    21.     }
    22. }

    * This source code was highlighted with Source Code Highlighter.


    Now, every implementation of ILogger.Write () will output measurements of the execution time of this method, isn’t it great?

    Materials





    In conclusion



    I hope this article gives a good start for your research in the field of quality code.

    PS This is my first post on the hub, so a little about myself : the horizon of my interests is very wide, in its technical component it is .NET development (ASP.NET, Sharepoint, WWF, Silverlight), development methods (Agile, Scrum, XP), development techniques (TDD, DDD, MDA, AOP).

    Also popular now: