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 go bust using the example of working with a Microsoft Unity container.
So let's get down to the theory:
Inversion of Control (IoC) and Dependency Injection (DI)
For the definition of IoC, we turn to
Wikipedia :
Inversion of Control * (IoC) is an important principle of object-oriented programming that is used to reduce connectivity in computer programs.
')
IoC is also known as 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 .NET languages.
* Immediately I wanted to make a reservation that I prefer not to use the Russian-language translation for IoC, but still if I am forced to do this, I will use it as a "control inversion"For the definition of DI also turn to
Wikipedia :
Dependency injection (eng. Dependency injection) refers to the process of providing external dependency to a software component and is a specific form of “inversion of control”, where changing the order of communication is the way to obtain the required dependency.
The classic example for determining how tightly your objects are linked to each other is to try to copy a class from your subject area to a new application and try to run it, if that doesn't work, then copy the related classes. Usually, as a result of these manipulations, your old application is almost entirely copied into the new one.
To resolve problems of dependencies of one object from another, usually an object that has a dependency is responsible for creating / obtaining the object it needs (I would like to draw your attention to patterns such as
Factory, Registry ).
There are a great many examples of implementation with IoC and DI casting a pseudo-code. Therefore, I don’t really want the article to grow because of them, and I can hardly provide you with a better understanding than with practical use.
I think it will be useful to
list the .NET DI / IoC containers here :
Aspect-oriented programming (AoP)
I admit I am a meticulous admirer of
Wikipedia :
Aspect-oriented programming (AOP) is a programming paradigm based on the idea of ​​separating functionality, especially cross-cutting functionality, to improve program partitioning into modules.
I would like to add that Aspect-oriented programming (AOP) is also intended to come to the aid of the PLO 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, and access control. You can argue and say that you can solve this problem by enveloping your business objects of the
Decorator template (
rus. ), 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 version of the
Enterprise Library to 4.1 , respectively, one of its components of the
Unity Application Block to version 1.2 . The Microsoft Enterprise Library is developed by the
patterns & practices group. The Microsoft Enterprise Library is a set of functional blocks designed to help developers do their usual routine tasks. Functional blocks - something like a manual, the source code provided in them can be used "as is", can be expanded or modified by developers according to 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 cache connectors.
- 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 across 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 features such as logging, caching, exception handling, and validation at the application level.
- Security Application Block . Developers can use this block to implement an application authorization and security mechanism.
- Unity Application Block . Developers can use this block as a lightweight, expandable dependency injection container with support for introducing dependencies into the constructor, the property and the method call, in the same way as the interception implementation, 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, injection-dependent container with support for adding dependencies to the constructor, the property and the method call, in the same way as the implementation of interception through extensions. You can use it 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 at several key points:
- You can use the Unity Application Block as a standalone dependency injection engine without needing an installed EntLib.
- The Unity Application Block can be configured using specialized configuration files or in run-time mode using your code.
- The Unity Application Block is independent of the core EntLib, exactly like the EntLib configuration system. It contains its own configuration mechanism, although if you prefer, you can use the EntLib configuration mechanism.
Long-awaited In Action
Requirements
For the example below, we’ll need:
- Installed .NET Framework 3.5 SP1
- Your favorite IDE (Notepad .. Visual Studio 2008 SP1 )
- Installed Unity
- 15-20 min time and some interest
Process
First, create a ConsoleApplication called UnityInAction1.
Next, add links to the following assembly:
- Microsoft.Pratices.ObjectBulder2
- Microsoft.Pratices.Unity
- Microsoft.Pratices.Unity.Interception.
Create an ILogger interface in our application:
namespace UnityInAction1 { interface ILogger { void Write( string msg); } }
* This source code was highlighted with Source Code Highlighter .
namespace UnityInAction1 { interface ILogger { void Write( string msg); } }
* This source code was highlighted with Source Code Highlighter .
namespace UnityInAction1 { interface ILogger { void Write( string msg); } }
* This source code was highlighted with Source Code Highlighter .
namespace UnityInAction1 { interface ILogger { void Write( string msg); } }
* This source code was highlighted with Source Code Highlighter .
namespace UnityInAction1 { interface ILogger { void Write( string msg); } }
* This source code was highlighted with Source Code Highlighter .
namespace UnityInAction1 { interface ILogger { void Write( string msg); } }
* This source code was highlighted with Source Code Highlighter .
namespace UnityInAction1 { interface ILogger { void Write( string msg); } }
* This source code was highlighted with Source Code Highlighter .
namespace UnityInAction1 { interface ILogger { void Write( string msg); } }
* This source code was highlighted with Source Code Highlighter .
namespace UnityInAction1 { interface ILogger { void Write( string msg); } }
* This source code was highlighted with Source Code Highlighter .
Next we implement it in the Logger class:
- using System;
- namespace UnityInAction1
- {
- class Logger: ILogger
- {
- #region ILogger Members
- public void Write ( string msg)
- {
- Console .WriteLine ();
- Console .WriteLine ( "*** In logger ***" );
- Console .WriteLine ( String .Format ( "message {0}" , msg));
- }
- #endregion
- }
- }
* This source code was highlighted with Source Code Highlighter .
So our usual application would look:
- using System;
- namespace UnityInAction1
- {
- class program
- {
- static void Main ( string [] args)
- {
- ILogger logger = new Logger ();
- logger.Write ( "My message" );
- Console .ReadKey ();
- }
- }
- }
* 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, so we want to place our Logger in a container (for example, in order to replace [and it will only be necessary to replace the container configuration site, and not the entire coverage code, as it usually happens] on the stub when testing):
- using System;
- using Microsoft.Practices.Unity;
- namespace UnityInAction1
- {
- class program
- {
- static void Main ( string [] args)
- {
- IUnityContainer container = new UnityContainer ();
- container.RegisterType <ILogger, Logger> ( new ContainerControlledLifetimeManager ());
- var logger = container.Resolve <ILogger> ();
- logger.Write ( "My message" );
- Console .ReadKey ();
- }
- }
- }
* This source code was highlighted with Source Code Highlighter .
Well, I think this example is quite enough to start.
Now we add the requirement for measuring the execution time of the ILogger.Write () method for all implementations of this interface, it is clear that with the help of the OOP, the implementation of this condition becomes more difficult, therefore we will look at this example from the point of view of AOP. First, let's override the description of ILogger by introducing a
new .NET
attribute :
- namespace UnityInAction1
- {
- interface ILogger
- {
- [Stopwatch]
- void Write ( string msg);
- }
- }
* This source code was highlighted with Source Code Highlighter .
Description of the Stopwatch attribute:
- using System;
- using Microsoft.Practices.Unity.InterceptionExtension;
- namespace UnityInAction1
- {
- class Stopwatch: HandlerAttribute
- {
- public override ICallHandler CreateHandler (Microsoft.Practices.Unity.IUnityContainer container)
- {
- return new StopwatchCallHandler ();
- }
- }
- public class StopwatchCallHandler: ICallHandler
- {
- public int Order { get ; set ;}
- public StopwatchCallHandler (): this (0) {}
- public StopwatchCallHandler ( int order)
- {
- Order = order;
- }
- #region ICallHandler Members
- public IMethodReturn Invoke (IMethodInvocation input, GetNextHandlerDelegate getNext)
- {
- System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch ();
- sw.Start ();
- var result = getNext (). Invoke (input, getNext);
- sw.Stop ();
- Console .WriteLine ();
- Console .WriteLine ( String .Format ( " Elapsed time {0} ms" , sw.ElapsedMilliseconds));
- return result;
- }
- #endregion
- }
- }
* This source code was highlighted with Source Code Highlighter .
Well, add an extension for our container:
- using System;
- using Microsoft.Practices.Unity;
- using Microsoft.Practices.Unity.InterceptionExtension;
- namespace UnityInAction1
- {
- class program
- {
- static void Main ( string [] args)
- {
- IUnityContainer container = new UnityContainer ();
- container.RegisterType <ILogger, Logger> ( new ContainerControlledLifetimeManager ());
- container.AddNewExtension <Interception> ();
- container.Configure <Interception> ()
- .SetInterceptorFor <ILogger> ( new TransparentProxyInterceptor ());
- var logger = container.Resolve <ILogger> ();
- logger.Write ( "My message" );
- Console .ReadKey ();
- }
- }
- }
* 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 that great?
Materials
In conclusion
I hope this article gives a good start to your research in the field of quality code.
PS This is my first post on Habré, 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 techniques (Agile, Scrum, XP), engineering techniques (TDD, DDD, MDA, AOP).